• Main Page
  • Classes
  • Files
  • File List
  • File Members

soundfile.cpp

Go to the documentation of this file.
00001 #include <cassert>
00002 #include <iostream>
00003 #include "soundfile.hpp"
00004 
00005 namespace 
00006 {
00007     const size_t MAX_FIXED_T_VAL=std::pow(2.0,(int)(8*sizeof(mad_fixed_t)-1)-1);
00008 }
00009 
00010 QString Soundfile::writeSound(const QString& fname, const real_vec& data,
00011         int samplerate, int format)
00012 {
00013     if (format == -1)
00014     {
00015         format = guessFormat(fname);
00016         if (!format)
00017             return "Unsupported filetype for writing.";
00018     }
00019     SF_INFO check = {0, samplerate, 1, format, 0, 0};
00020     if (!sf_format_check(&check))
00021         return "Format didn't pass sf_format_check()"; // shouldn't happen
00022 
00023     //XXX zmeni unicode nazvy
00024     SndfileHandle file(fname.toLocal8Bit(), SFM_WRITE, format, 1, samplerate);
00025     if (!file)
00026         assert(false);
00027     if (file.error())
00028         return file.strError();
00029 
00030     file.writef(&data[0], data.size());
00031     return QString();
00032 }
00033 
00035 int Soundfile::guessFormat(const QString& filename)
00036 {
00037     assert(!filename.isNull());
00038     if (filename.endsWith(".wav"))
00039         return SF_FORMAT_WAV|SF_FORMAT_PCM_16;
00040     else if (filename.endsWith(".ogg"))
00041         return SF_FORMAT_OGG|SF_FORMAT_VORBIS;
00042     else if (filename.endsWith(".flac"))
00043         return SF_FORMAT_FLAC|SF_FORMAT_PCM_16;
00044     return 0;
00045 }
00046 
00047 Soundfile::Soundfile()
00048     : data_(NULL)
00049 {
00050 }
00051 
00052 Soundfile::Soundfile(const QString& filename)
00053 {
00054     load(filename);
00055 }
00056 
00057 real_vec Soundfile::read_channel(int channel)
00058 {
00059     return data_->read_channel(channel);
00060 }
00061 
00062 bool Soundfile::valid() const
00063 {
00064     return data_ != NULL;
00065 }
00066 
00067 const QString& Soundfile::error() const
00068 {
00069     return error_;
00070 }
00071 
00072 void Soundfile::load(const QString& filename)
00073 {
00074     if (filename.endsWith(".mp3"))
00075         data_ = new MP3Data(filename);
00076     else
00077         data_ = new SndfileData(filename);
00078 
00079     if (!data_->valid())
00080     {
00081         error_ = data_->error();
00082         delete data_;
00083         data_ = NULL;
00084     }
00085 }
00086 
00087 void Soundfile::reset()
00088 {
00089     delete data_;
00090     data_ = NULL;
00091 }
00092 
00093 const SoundfileData& Soundfile::data() const
00094 {
00095     assert(data_ != NULL);
00096     return *data_;
00097 }
00098 
00099 // ----
00100 
00101 SndfileData::SndfileData(const QString& filename)
00102 {
00103     file_ = SndfileHandle(filename.toLocal8Bit());
00104 }
00105 
00106 bool SndfileData::valid() const
00107 {
00108     return (file_ && !file_.error());
00109 }
00110 
00111 QString SndfileData::error() const
00112 {
00113     return file_.strError();
00114 }
00115 
00116 size_t SndfileData::frames() const
00117 {
00118     return file_.frames();
00119 }
00120 
00121 double SndfileData::length() const
00122 {
00123     return (double)frames()/samplerate();
00124 }
00125 
00126 int SndfileData::channels() const
00127 {
00128     return file_.channels();
00129 }
00130 
00131 int SndfileData::samplerate() const
00132 {
00133     return file_.samplerate();
00134 }
00135 
00136 real_vec SndfileData::read_channel(int channel)
00137 {
00138     assert(channel < channels());
00139     real_vec buffer(frames()*channels());
00140     file_.readf(&buffer[0], frames());
00141     //size_t frames_read = file_.readf(&buffer[0], frames());
00142     //assert(frames_read == frames());
00143     file_.seek(0, SEEK_SET);
00144 
00145     if (channels() > 1)
00146     {
00147         for (size_t i = channel, j = 0; j < frames(); i += channels(), ++j)
00148             buffer[j] = buffer[i];
00149         buffer.resize(frames());
00150     }
00151     return buffer;
00152 }
00153 
00154 SndfileData::~SndfileData()
00155 {
00156 }
00157 
00158 // ---
00159 
00160 MP3Data::MP3Data(const QString& fname)
00161     : frames_(0)
00162     , length_(0)
00163     , samplerate_(0)
00164     , channels_(0)
00165     , filename_(fname)
00166 {
00167     get_mp3_stats();
00168 }
00169 
00170 void MP3Data::get_mp3_stats()
00171 {
00172     mad_stream stream;
00173     mad_header header;
00174     mad_stream_init(&stream);
00175     mad_header_init(&header);
00176 
00177     QFile file(filename_);
00178     if (!file.open(QIODevice::ReadOnly))
00179     {
00180         error_ = "Error opening file.";
00181         goto cleanup;
00182     }
00183     {
00184     uchar* buf = file.map(0, file.size());
00185     mad_stream_buffer(&stream, buf, file.size());
00186 
00187     while (true)
00188     {
00189         if (mad_header_decode(&header, &stream) == -1)
00190         {
00191             if (stream.error == MAD_ERROR_LOSTSYNC)
00192                 continue;
00193             else if (stream.error == MAD_ERROR_BUFLEN)
00194                 break;
00195             else
00196             {
00197                 error_ = "Error decoding mp3 headers!";
00198                 break;
00199             }
00200         }
00201         frames_++;
00202         length_ += header.duration.fraction;
00203         if (!samplerate_)
00204         {
00205             samplerate_ = header.samplerate;
00206             if (header.mode == MAD_MODE_SINGLE_CHANNEL)
00207                 channels_ = 1;
00208             else
00209                 channels_ = 2;
00210         }
00211     }
00212     length_ /= MAD_TIMER_RESOLUTION;
00213     if (!samplerate_)
00214         error_ = "Invalid mp3 file.";
00215     }
00216 cleanup:
00217     mad_stream_finish(&stream);
00218     mad_header_finish(&header);
00219 }
00220 
00221 QString MP3Data::error() const
00222 {
00223     return error_;
00224 }
00225 
00226 real_vec MP3Data::read_channel(int channel)
00227 {
00228     mad_stream stream;
00229     mad_frame frame;
00230     mad_synth synth;
00231     mad_stream_init(&stream);
00232     mad_frame_init(&frame);
00233     mad_synth_init(&synth);
00234 
00235     real_vec result;
00236 
00237     QFile file(filename_);
00238     if (!file.open(QIODevice::ReadOnly))
00239         goto cleanup;
00240     {
00241     uchar* buf = file.map(0, file.size());
00242     mad_stream_buffer(&stream, buf, file.size());
00243 
00244     while (true)
00245     {
00246         if (mad_frame_decode(&frame, &stream) == -1)
00247         {
00248             if (stream.error == MAD_ERROR_LOSTSYNC)
00249                 continue;
00250             else if (stream.error == MAD_ERROR_BUFLEN)
00251                 break;
00252             else
00253             {
00254                 error_ = "Error decoding mp3 file.";
00255                 break;
00256             }
00257         }
00258         mad_synth_frame(&synth, &frame);
00259         mad_fixed_t* samples = synth.pcm.samples[channel];
00260         for (short i = 0; i < synth.pcm.length; ++i)
00261             result.push_back((double)samples[i]/MAX_FIXED_T_VAL);
00262     }
00263     }
00264 cleanup:
00265     mad_synth_finish(&synth);
00266     mad_frame_finish(&frame);
00267     mad_stream_finish(&stream);
00268 
00269     return result;
00270 }
00271 
00272 size_t MP3Data::frames() const
00273 {
00274     return frames_;
00275 }
00276 
00277 double MP3Data::length() const//in seconds
00278 {
00279     return length_;
00280 }
00281 
00282 int MP3Data::samplerate() const
00283 {
00284     return samplerate_;
00285 }
00286 
00287 int MP3Data::channels() const
00288 {
00289     return channels_;
00290 }
00291 
00292 bool MP3Data::valid() const
00293 {
00294     return error_.isEmpty();
00295 }

Generated by  doxygen 1.7.1