int MP3ImportFileHandle::Import(TrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) { outTracks.clear(); CreateProgress(); /* Prepare decoder data, initialize decoder */ mPrivateData.file = mFile; mPrivateData.inputBuffer = new unsigned char [INPUT_BUFFER_SIZE]; mPrivateData.progress = mProgress.get(); mPrivateData.updateResult= eProgressSuccess; mPrivateData.id3checked = false; mPrivateData.numChannels = 0; mPrivateData.trackFactory= trackFactory; mad_decoder_init(&mDecoder, &mPrivateData, input_cb, 0, 0, output_cb, error_cb, 0); /* and send the decoder on its way! */ bool res = (mad_decoder_run(&mDecoder, MAD_DECODER_MODE_SYNC) == 0) && (mPrivateData.numChannels > 0) && !(mPrivateData.updateResult == eProgressCancelled) && !(mPrivateData.updateResult == eProgressFailed); mad_decoder_finish(&mDecoder); delete[] mPrivateData.inputBuffer; if (!res) { /* failure */ /* printf("failure\n"); */ return (mPrivateData.updateResult); } /* success */ /* printf("success\n"); */ /* copy the WaveTrack pointers into the Track pointer list that * we are expected to fill */ for(const auto &channel : mPrivateData.channels) { channel->Flush(); } outTracks.swap(mPrivateData.channels); /* Read in any metadata */ ImportID3(tags); return mPrivateData.updateResult; }
ProgressResult QTImportFileHandle::Import(TrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) { outTracks.clear(); OSErr err = noErr; MovieAudioExtractionRef maer = NULL; auto updateResult = ProgressResult::Success; auto totSamples = (sampleCount) GetMovieDuration(mMovie); // convert from TimeValue decltype(totSamples) numSamples = 0; Boolean discrete = true; UInt32 quality = kQTAudioRenderQuality_Max; AudioStreamBasicDescription desc; UInt32 maxSampleSize; bool res = false; auto cleanup = finally( [&] { if (maer) { MovieAudioExtractionEnd(maer); } } ); CreateProgress(); do { err = MovieAudioExtractionBegin(mMovie, 0, &maer); if (err != noErr) { AudacityMessageBox(_("Unable to start QuickTime extraction")); break; } err = MovieAudioExtractionSetProperty(maer, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_RenderQuality, sizeof(quality), &quality); if (err != noErr) { AudacityMessageBox(_("Unable to set QuickTime render quality")); break; } err = MovieAudioExtractionSetProperty(maer, kQTPropertyClass_MovieAudioExtraction_Movie, kQTMovieAudioExtractionMoviePropertyID_AllChannelsDiscrete, sizeof(discrete), &discrete); if (err != noErr) { AudacityMessageBox(_("Unable to set QuickTime discrete channels property")); break; } err = MovieAudioExtractionGetProperty(maer, kQTPropertyClass_MovieAudioExtraction_Audio, kQTAudioPropertyID_MaxAudioSampleSize, sizeof(maxSampleSize), &maxSampleSize, NULL); if (err != noErr) { AudacityMessageBox(_("Unable to get QuickTime sample size property")); break; } err = MovieAudioExtractionGetProperty(maer, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, sizeof(desc), &desc, NULL); if (err != noErr) { AudacityMessageBox(_("Unable to retrieve stream description")); break; } auto numchan = desc.mChannelsPerFrame; const size_t bufsize = 5 * desc.mSampleRate; // determine sample format sampleFormat format; switch (maxSampleSize) { case 16: format = int16Sample; break; case 24: format = int24Sample; break; default: format = floatSample; break; } // Allocate an array of pointers, whose size is not known statically, // and prefixed with the AudioBufferList structure. MallocPtr< AudioBufferList > abl{ static_cast< AudioBufferList * >( calloc( 1, offsetof( AudioBufferList, mBuffers ) + (sizeof(AudioBuffer) * numchan))) }; abl->mNumberBuffers = numchan; TrackHolders channels{ numchan }; const auto size = sizeof(float) * bufsize; ArraysOf<unsigned char> holders{ numchan, size }; for (size_t c = 0; c < numchan; c++) { auto &buffer = abl->mBuffers[c]; auto &holder = holders[c]; auto &channel = channels[c]; buffer.mNumberChannels = 1; buffer.mDataByteSize = size; buffer.mData = holder.get(); channel = trackFactory->NewWaveTrack( format ); channel->SetRate( desc.mSampleRate ); if (numchan == 2) { if (c == 0) { channel->SetChannel(Track::LeftChannel); channel->SetLinked(true); } else if (c == 1) { channel->SetChannel(Track::RightChannel); } } } do { UInt32 flags = 0; UInt32 numFrames = bufsize; err = MovieAudioExtractionFillBuffer(maer, &numFrames, abl.get(), &flags); if (err != noErr) { AudacityMessageBox(_("Unable to get fill buffer")); break; } for (size_t c = 0; c < numchan; c++) { channels[c]->Append((char *) abl->mBuffers[c].mData, floatSample, numFrames); } numSamples += numFrames; updateResult = mProgress->Update( numSamples.as_long_long(), totSamples.as_long_long() ); if (numFrames == 0 || flags & kQTMovieAudioExtractionComplete) { break; } } while (updateResult == ProgressResult::Success); res = (updateResult == ProgressResult::Success && err == noErr); if (res) { for (const auto &channel: channels) { channel->Flush(); } outTracks.swap(channels); } // // Extract any metadata // if (res) { AddMetadata(tags); } } while (false); // done: return (res ? ProgressResult::Success : ProgressResult::Failed); }
int FLACImportFileHandle::Import(TrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) { outTracks.clear(); wxASSERT(mStreamInfoDone); CreateProgress(); mChannels.resize(mNumChannels); auto iter = mChannels.begin(); for (int c = 0; c < mNumChannels; ++iter, ++c) { *iter = trackFactory->NewWaveTrack(mFormat, mSampleRate); if (mNumChannels == 2) { switch (c) { case 0: iter->get()->SetChannel(Track::LeftChannel); iter->get()->SetLinked(true); break; case 1: iter->get()->SetChannel(Track::RightChannel); break; } } else { iter->get()->SetChannel(Track::MonoChannel); } } //Start OD bool useOD = false; #ifdef EXPERIMENTAL_OD_FLAC useOD=true; #endif // TODO: Vigilant Sentry: Variable res unused after assignment (error code DA1) // Should check the result. #ifdef LEGACY_FLAC bool res = (mFile->process_until_end_of_file() != 0); #else bool res = true; if(!useOD) res = (mFile->process_until_end_of_stream() != 0); #endif wxUnusedVar(res); //add the task to the ODManager if(useOD) { sampleCount fileTotalFrames = mNumSamples; sampleCount maxBlockSize = mChannels.begin()->get()->GetMaxBlockSize(); for (sampleCount i = 0; i < fileTotalFrames; i += maxBlockSize) { sampleCount blockLen = maxBlockSize; if (i + blockLen > fileTotalFrames) blockLen = fileTotalFrames - i; auto iter = mChannels.begin(); for (int c = 0; c < mNumChannels; ++c, ++iter) iter->get()->AppendCoded(mFilename, i, blockLen, c, ODTask::eODFLAC); mUpdateResult = mProgress->Update(i, fileTotalFrames); if (mUpdateResult != eProgressSuccess) break; } bool moreThanStereo = mNumChannels>2; for (const auto &channel : mChannels) { mDecoderTask->AddWaveTrack(channel.get()); if(moreThanStereo) { //if we have 3 more channels, they get imported on seperate tracks, so we add individual tasks for each. ODManager::Instance()->AddNewTask(mDecoderTask); mDecoderTask=new ODDecodeFlacTask; //TODO: see if we need to use clone to keep the metadata. } } //if we have mono or a linked track (stereo), we add ONE task for the one linked wave track if(!moreThanStereo) ODManager::Instance()->AddNewTask(mDecoderTask); } //END OD if (mUpdateResult == eProgressFailed || mUpdateResult == eProgressCancelled) { return mUpdateResult; } for (const auto &channel : mChannels) { channel->Flush(); } outTracks.swap(mChannels); tags->Clear(); size_t cnt = mFile->mComments.GetCount(); for (int c = 0; c < cnt; c++) { wxString name = mFile->mComments[c].BeforeFirst(wxT('=')); wxString value = mFile->mComments[c].AfterFirst(wxT('=')); if (name.Upper() == wxT("DATE") && !tags->HasTag(TAG_YEAR)) { long val; if (value.Length() == 4 && value.ToLong(&val)) { name = TAG_YEAR; } } tags->SetTag(name, value); } return mUpdateResult; }