svcore  1.9
WavFileWriter.cpp
Go to the documentation of this file.
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