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()";
00022
00023
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
00142
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
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 }