bool EffectEcho::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap)) { if (delay == 0.0) { return false; } histPos = 0; auto requestedHistLen = (sampleCount) (mSampleRate * delay); // Guard against extreme delay values input by the user try { // Guard against huge delay values from the user. // Don't violate the assertion in as_size_t if (requestedHistLen != (histLen = static_cast<size_t>(requestedHistLen.as_long_long()))) throw std::bad_alloc{}; history = new float[histLen]; } catch ( const std::bad_alloc& ) { wxMessageBox(_("Requested value exceeds memory capacity.")); return false; } memset(history, 0, sizeof(float) * histLen); return history != NULL; }
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); }
bool VampEffect::Process() { if (!mPlugin) { return false; } int count = 0; bool multiple = false; unsigned prevTrackChannels = 0; if (GetNumWaveGroups() > 1) { // if there is another track beyond this one and any linked one, // then we're processing more than one track. That means we // should use the originating track name in each NEW label // track's name, to make clear which is which multiple = true; } std::vector<std::shared_ptr<Effect::AddedAnalysisTrack>> addedTracks; for (auto leader : inputTracks()->Leaders<const WaveTrack>()) { auto channelGroup = TrackList::Channels(leader); auto left = *channelGroup.first++; sampleCount lstart, rstart = 0; sampleCount len; GetSamples(left, &lstart, &len); unsigned channels = 1; // channelGroup now contains all but the first channel const WaveTrack *right = channelGroup.size() ? *channelGroup.first++ : nullptr; if (right) { channels = 2; GetSamples(right, &rstart, &len); } // TODO: more-than-two-channels size_t step = mPlugin->getPreferredStepSize(); size_t block = mPlugin->getPreferredBlockSize(); bool initialiseRequired = true; if (block == 0) { if (step != 0) { block = step; } else { block = 1024; } } if (step == 0) { step = block; } if (prevTrackChannels > 0) { // Plugin has already been initialised, so if the number of // channels remains the same, we only need to do a reset. // Otherwise we need to re-construct the whole plugin, // because a Vamp plugin can't be re-initialised. if (prevTrackChannels == channels) { mPlugin->reset(); initialiseRequired = false; } else { //!!! todo: retain parameters previously set Init(); } } if (initialiseRequired) { if (!mPlugin->initialise(channels, step, block)) { Effect::MessageBox(_("Sorry, Vamp Plug-in failed to initialize.")); return false; } } const auto effectName = GetSymbol().Translation(); addedTracks.push_back(AddAnalysisTrack( multiple ? wxString::Format( _("%s: %s"), left->GetName(), effectName ) : effectName )); LabelTrack *ltrack = addedTracks.back()->get(); FloatBuffers data{ channels, block }; auto originalLen = len; auto ls = lstart; auto rs = rstart; while (len != 0) { const auto request = limitSampleBufferSize( block, len ); if (left) { left->Get((samplePtr)data[0].get(), floatSample, ls, request); } if (right) { right->Get((samplePtr)data[1].get(), floatSample, rs, request); } if (request < block) { for (unsigned int c = 0; c < channels; ++c) { for (decltype(block) i = request; i < block; ++i) { data[c][i] = 0.f; } } } // UNSAFE_SAMPLE_COUNT_TRUNCATION // Truncation in case of very long tracks! Vamp::RealTime timestamp = Vamp::RealTime::frame2RealTime( long( ls.as_long_long() ), (int)(mRate + 0.5) ); Vamp::Plugin::FeatureSet features = mPlugin->process( reinterpret_cast< float** >( data.get() ), timestamp); AddFeatures(ltrack, features); if (len > (int)step) { len -= step; } else { len = 0; } ls += step; rs += step; if (channels > 1) { if (TrackGroupProgress(count, (ls - lstart).as_double() / originalLen.as_double() )) { return false; } } else { if (TrackProgress(count, (ls - lstart).as_double() / originalLen.as_double() )) { return false; } } } Vamp::Plugin::FeatureSet features = mPlugin->getRemainingFeatures(); AddFeatures(ltrack, features); prevTrackChannels = channels; } // All completed without cancellation, so commit the addition of tracks now for (auto &addedTrack : addedTracks) addedTrack->Commit(); return true; }