svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006 Chris Cannam and QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include "WavFileWriter.h" 00017 00018 #include "model/DenseTimeValueModel.h" 00019 #include "base/Selection.h" 00020 #include "base/TempWriteFile.h" 00021 #include "base/Exceptions.h" 00022 00023 #include <QFileInfo> 00024 00025 #include <iostream> 00026 00027 WavFileWriter::WavFileWriter(QString path, 00028 int sampleRate, 00029 int channels, 00030 FileWriteMode mode) : 00031 m_path(path), 00032 m_sampleRate(sampleRate), 00033 m_channels(channels), 00034 m_temp(0), 00035 m_file(0) 00036 { 00037 SF_INFO fileInfo; 00038 fileInfo.samplerate = m_sampleRate; 00039 fileInfo.channels = m_channels; 00040 fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; 00041 00042 try { 00043 if (mode == WriteToTemporary) { 00044 m_temp = new TempWriteFile(m_path); 00045 m_file = sf_open(m_temp->getTemporaryFilename().toLocal8Bit(), 00046 SFM_WRITE, &fileInfo); 00047 if (!m_file) { 00048 cerr << "WavFileWriter: Failed to open file (" 00049 << sf_strerror(m_file) << ")" << endl; 00050 m_error = QString("Failed to open audio file '%1' for writing") 00051 .arg(m_temp->getTemporaryFilename()); 00052 } 00053 } else { 00054 m_file = sf_open(m_path.toLocal8Bit(), SFM_WRITE, &fileInfo); 00055 if (!m_file) { 00056 cerr << "WavFileWriter: Failed to open file (" 00057 << sf_strerror(m_file) << ")" << endl; 00058 m_error = QString("Failed to open audio file '%1' for writing") 00059 .arg(m_path); 00060 } 00061 } 00062 } catch (FileOperationFailed &f) { 00063 m_error = f.what(); 00064 m_temp = 0; 00065 m_file = 0; 00066 } 00067 } 00068 00069 WavFileWriter::~WavFileWriter() 00070 { 00071 if (m_file) close(); 00072 } 00073 00074 bool 00075 WavFileWriter::isOK() const 00076 { 00077 return (m_error.isEmpty()); 00078 } 00079 00080 QString 00081 WavFileWriter::getError() const 00082 { 00083 return m_error; 00084 } 00085 00086 QString 00087 WavFileWriter::getWriteFilename() const 00088 { 00089 if (m_temp) { 00090 return m_temp->getTemporaryFilename(); 00091 } else { 00092 return m_path; 00093 } 00094 } 00095 00096 bool 00097 WavFileWriter::writeModel(DenseTimeValueModel *source, 00098 MultiSelection *selection) 00099 { 00100 if (source->getChannelCount() != m_channels) { 00101 SVDEBUG << "WavFileWriter::writeModel: Wrong number of channels (" 00102 << source->getChannelCount() << " != " << m_channels << ")" 00103 << endl; 00104 m_error = QString("Failed to write model to audio file '%1'") 00105 .arg(getWriteFilename()); 00106 return false; 00107 } 00108 00109 if (!m_file) { 00110 m_error = QString("Failed to write model to audio file '%1': File not open") 00111 .arg(getWriteFilename()); 00112 return false; 00113 } 00114 00115 bool ownSelection = false; 00116 if (!selection) { 00117 selection = new MultiSelection; 00118 selection->setSelection(Selection(source->getStartFrame(), 00119 source->getEndFrame())); 00120 ownSelection = true; 00121 } 00122 00123 int bs = 2048; 00124 float *ub = new float[bs]; // uninterleaved buffer (one channel) 00125 float *ib = new float[bs * m_channels]; // interleaved buffer 00126 00127 for (MultiSelection::SelectionList::iterator i = 00128 selection->getSelections().begin(); 00129 i != selection->getSelections().end(); ++i) { 00130 00131 int f0(i->getStartFrame()), f1(i->getEndFrame()); 00132 00133 for (int f = f0; f < f1; f += bs) { 00134 00135 int n = std::min(bs, f1 - f); 00136 00137 for (int c = 0; c < int(m_channels); ++c) { 00138 source->getData(c, f, n, ub); 00139 for (int i = 0; i < n; ++i) { 00140 ib[i * m_channels + c] = ub[i]; 00141 } 00142 } 00143 00144 sf_count_t written = sf_writef_float(m_file, ib, n); 00145 00146 if (written < n) { 00147 m_error = QString("Only wrote %1 of %2 frames at file frame %3") 00148 .arg(written).arg(n).arg(f); 00149 break; 00150 } 00151 } 00152 } 00153 00154 delete[] ub; 00155 delete[] ib; 00156 if (ownSelection) delete selection; 00157 00158 return isOK(); 00159 } 00160 00161 bool 00162 WavFileWriter::writeSamples(float **samples, int count) 00163 { 00164 if (!m_file) { 00165 m_error = QString("Failed to write model to audio file '%1': File not open") 00166 .arg(getWriteFilename()); 00167 return false; 00168 } 00169 00170 float *b = new float[count * m_channels]; 00171 for (int i = 0; i < int(count); ++i) { 00172 for (int c = 0; c < int(m_channels); ++c) { 00173 b[i * m_channels + c] = samples[c][i]; 00174 } 00175 } 00176 00177 sf_count_t written = sf_writef_float(m_file, b, count); 00178 00179 delete[] b; 00180 00181 if (written < int(count)) { 00182 m_error = QString("Only wrote %1 of %2 frames") 00183 .arg(written).arg(count); 00184 } 00185 00186 return isOK(); 00187 } 00188 00189 bool 00190 WavFileWriter::close() 00191 { 00192 if (m_file) { 00193 sf_close(m_file); 00194 m_file = 0; 00195 } 00196 if (m_temp) { 00197 m_temp->moveToTarget(); 00198 delete m_temp; 00199 m_temp = 0; 00200 } 00201 return true; 00202 } 00203