AlgorithmStatus OverlapAdd::process() { EXEC_DEBUG("process()"); AlgorithmStatus status = acquireData(); EXEC_DEBUG("data acquired"); if (status != OK) { if (!shouldStop()) return status; int available = input("frame").available(); if (available == 0) { return FINISHED; } // otherwise, there are still some frames return CONTINUE; } const vector<vector<Real> >& frames = _frames.tokens(); vector<Real>& output = _output.tokens(); assert(frames.size() == 1 && (int) output.size() == _hopSize); const vector<Real> & windowedFrame = frames[0]; if (windowedFrame.empty()) throw EssentiaException("OverlapAdd: the input frame is empty"); processFrame(_tmpFrame, windowedFrame, output, _frameHistory, _frameSize, _hopSize, _normalizationGain); EXEC_DEBUG("releasing"); releaseData(); EXEC_DEBUG("released"); return OK; }
AlgorithmStatus SilenceRate::process() { EXEC_DEBUG("process()"); AlgorithmStatus status = acquireData(); if (status != OK) return status; const vector<Real>& frame = _frame.firstToken(); if (frame.empty()) { throw EssentiaException("SilenceRate: a given input frame was empty, " "cannot compute the power of an empty frame."); } Real power = instantPower(frame); for (int i=0; i<(int)_outputs.size(); i++) { Real& output = _outputs[i]->firstToken(); output = power < _thresholds[i]? 1.0 : 0.0; } releaseData(); return OK; }
AlgorithmStatus AccumulatorAlgorithm::process() { EXEC_DEBUG("process()"); AlgorithmStatus status = acquireData(); if (status == OK) { consume(); releaseData(); return OK; } // status != SYNC_OK: we couldn't acquire a sufficient number of tokens... // if we're not yet at the end of the stream, just return and wait for more if (!shouldStop()) return status; // most likely NO_INPUT // we are at the end of the stream, we need to work with what's available int available = _inputStream->available(); EXEC_DEBUG("EOS; there are " << available << " available tokens left"); if (available > 0) { _inputStream->setAcquireSize(available); _inputStream->setReleaseSize(available); status = acquireData(); if (status != OK) { throw EssentiaException("Accumulator EOS internal scheduling error..."); } // consume our very last tokens consume(); releaseData(); } // and now the big moment we've been waiting for all the time! All the tokens // from the input stream have been consumed, it is time to output our final result finalProduce(); return FINISHED; // yes we produced something, and we're done! }
AlgorithmStatus FrameCutter::process() { bool lastFrame = false; EXEC_DEBUG("process()"); // if _streamIndex < _startIndex, we need to advance into the stream until we // arrive at _startIndex if (_streamIndex < _startIndex) { // to make sure we can skip that many, use frameSize (buffer has been resized // to be able to accomodate at least that many sample before starting processing) int skipSize = _frameSize; int howmuch = min(_startIndex - _streamIndex, skipSize); _audio.setAcquireSize(howmuch); _audio.setReleaseSize(howmuch); _frames.setAcquireSize(0); _frames.setReleaseSize(0); if (acquireData() != OK) return NO_INPUT; releaseData(); _streamIndex += howmuch; return OK; } // need to know whether we have to zero-pad on the left: ie, _startIndex < 0 int zeropadSize = 0; int acquireSize = _frameSize; int releaseSize = min(_hopSize, _frameSize); // in case hopsize > framesize int available = _audio.available(); // we need this check anyway because we might be at the very end of the stream and try to acquire 0 // for our last frame, which will unfortunately work, so just get rid of this case right now if (available == 0) return NO_INPUT; if (_startIndex < 0) { // left zero-padding and only acquire as much as _frameSize + startIndex tokens and should release zero acquireSize = _frameSize + _startIndex; releaseSize = 0; zeropadSize = -_startIndex; } // if there are not enough tokens in the stream (howmuch < available): if (acquireSize >= available) { // has to be >= in case the size of the audio fits exactly with frameSize & hopSize if (!shouldStop()) return NO_INPUT; // not end of stream -> return and wait for more data to come acquireSize = available; // need to acquire what's left releaseSize = _startIndex >= 0 ? min(available, _hopSize) : 0; // cannot release more tokens than there are available if (_startFromZero) { if (_lastFrameToEndOfFile) { if (_startIndex >= _streamIndex+available) lastFrame = true; } else lastFrame = true; } else { if (_startIndex + _frameSize/2 >= _streamIndex + available) // center of frame >= end of stream lastFrame = true; } } _frames.setAcquireSize(1); _frames.setReleaseSize(1); _audio.setAcquireSize(acquireSize); _audio.setReleaseSize(releaseSize); /* EXEC_DEBUG("zeropadSize: " << zeropadSize << "\tacquireSize: " << acquireSize << "\treleaseSize: " << releaseSize << "\tavailable: " << available << "\tlast frame: " << lastFrame << "\tstartIndex: " << _startIndex << "\tstreamIndex: " << _streamIndex); */ AlgorithmStatus status = acquireData(); EXEC_DEBUG("data acquired (audio: " << acquireSize << " - frames: 1)"); if (status != OK) { if (status == NO_INPUT) return NO_INPUT; if (status == NO_OUTPUT) return NO_OUTPUT; throw EssentiaException("FrameCutter: something weird happened."); } // some semantic description to not get mixed up between the 2 meanings // of a vector<Real> (which acts both as a stream of Real tokens at the // input and as a single vector<Real> token at the output) typedef vector<AudioSample> Frame; // get the audio input and copy it as a frame to the output const vector<AudioSample>& audio = _audio.tokens(); Frame& frame = _frames.firstToken(); frame.resize(_frameSize); // left zero-padding of the frame int idxInFrame = 0; for (; idxInFrame < zeropadSize; idxInFrame++) { frame[idxInFrame] = (Real)0.0; } fastcopy(frame.begin()+idxInFrame, audio.begin(), acquireSize); idxInFrame += acquireSize; // check if the idxInFrame is below the threshold (this would only happen // for the last frame in the stream) and if so, don't produce data if (idxInFrame < _validFrameThreshold) { E_INFO("FrameCutter: dropping incomplete frame"); // release inputs (advance to next frame), but not the output frame (we didn't produce anything) _audio.release(_audio.releaseSize()); return NO_INPUT; } // right zero-padding on the last frame for (; idxInFrame < _frameSize; idxInFrame++) { frame[idxInFrame] = (Real)0.0; } _startIndex += _hopSize; if (isSilent(frame)) { switch (_silentFrames) { case DROP: E_INFO("FrameCutter: dropping silent frame"); // release inputs (advance to next frame), but not the output frame (we didn't produce anything) _audio.release(_audio.releaseSize()); return OK; case ADD_NOISE: { vector<AudioSample> inputFrame(_frameSize, 0.0); fastcopy(&inputFrame[0]+zeropadSize, &frame[0], acquireSize); _noiseAdder->input("signal").set(inputFrame); _noiseAdder->output("signal").set(frame); _noiseAdder->compute(); break; } // otherwise, don't do nothing... case KEEP: default: ; } } EXEC_DEBUG("produced frame; releasing"); releaseData(); _streamIndex += _audio.releaseSize(); EXEC_DEBUG("released"); if (lastFrame) return PASS; return OK; }
AlgorithmStatus AudioOnsetsMarker::process() { EXEC_DEBUG("process()"); AlgorithmStatus status = acquireData(); EXEC_DEBUG("data acquired"); if (status != OK) { if (!shouldStop()) return status; int available = input("signal").available(); if (available == 0) return FINISHED; // otherwise, there's still some audio we can gobble up input("signal").setAcquireSize(available); input("signal").setReleaseSize(available); output("signal").setAcquireSize(available); output("signal").setReleaseSize(available); return CONTINUE; } const vector<Real>& input = _input.tokens(); vector<Real>& output = _output.tokens(); assert(output.size() == input.size()); Real out = 0; for (int i=0; i<int(input.size()); i++) { if (_onsetIdx >= (int)_onsets.size()) { out = 0.5*input[i]; } else { if (_processedSamples >= int(_onsets[_onsetIdx]) && _processedSamples <= int(_onsets[_onsetIdx] + _burst.size())) { // check whether next onset is closer than noise.size(): if (_onsetIdx < (int)_onsets.size()-1) { if (_processedSamples == int(_onsets[_onsetIdx+1])) { _burstIdx = 0; //cout << "onsetsmarker processing onset: " << _onsetIdx << "/" << _onsets.size() << " at " << _onsets[_onsetIdx]/_sampleRate << " processedSamples: " << _processedSamples/_sampleRate << endl; _onsetIdx++; while (_onsetIdx < (int)_onsets.size() && _processedSamples > _onsets[_onsetIdx]) { _onsetIdx++; } } } out = 0.5*(input[i]+_burst[_burstIdx++]); if (_burstIdx >= (int)_burst.size()) { _burstIdx = 0; //cout << "onsetsmarker processing onset: " << _onsetIdx << "/" << _onsets.size() << " at " << _onsets[_onsetIdx]/_sampleRate << " processedSamples: " << _processedSamples/_sampleRate << endl; _onsetIdx++; while (_onsetIdx < (int)_onsets.size() && _processedSamples > _onsets[_onsetIdx]) { _onsetIdx++; } } } else { out = 0.5*input[i]; } } output[i] = out; _processedSamples++; //cout << "onsetIdx: " << _onsetIdx << " pos: " << _onsets[_onsetIdx] << "onsetsSize: " << _onsets.size() << " processedSamples: " << _processedSamples << endl; } EXEC_DEBUG("releasing"); releaseData(); EXEC_DEBUG("released"); return OK; }
AlgorithmStatus Resample::process() { EXEC_DEBUG("process()"); EXEC_DEBUG("Trying to acquire data"); AlgorithmStatus status = acquireData(); if (status != OK) { // FIXME: are we sure this still works? // if status == NO_OUTPUT, we should temporarily stop the resampler, // return from this function so its dependencies can process the frames, // and reschedule the framecutter to run when all this is done. if (status == NO_OUTPUT) { EXEC_DEBUG("no more output available for resampling; mark it for rescheduling and return"); //_reschedule = true; return NO_OUTPUT; // if the buffer is full, we need to have produced something! } // if shouldStop is true, that means there is no more audio, so we need // to take what's left to fill in the output, instead of waiting for more // data to come in (which would have done by returning from this function) if (!shouldStop()) return NO_INPUT; int available = input("signal").available(); EXEC_DEBUG("There are " << available << " available tokens"); if (available == 0) return NO_INPUT; input("signal").setAcquireSize(available); input("signal").setReleaseSize(available); output("signal").setAcquireSize((int)(_data.src_ratio * available + 100 + (int)_delay)); _data.end_of_input = 1; return process(); } EXEC_DEBUG("data acquired"); const vector<AudioSample>& signal = _signal.tokens(); vector<AudioSample>& resampled = _resampled.tokens(); EXEC_DEBUG("signal size:" << signal.size()); EXEC_DEBUG("resampled size:" << resampled.size()); _data.data_in = const_cast<float*>(&(signal[0])); _data.input_frames = (long)signal.size(); _data.data_out = &(resampled[0]); _data.output_frames = (long)resampled.size(); if (_data.src_ratio == 1.0) { assert(_data.output_frames >= _data.input_frames); fastcopy(_data.data_out, _data.data_in, _data.input_frames); _data.input_frames_used = _data.input_frames; _data.output_frames_gen = _data.input_frames; } else { int error = src_process(_state, &_data); if (error) { throw EssentiaException("Resample: ", src_strerror(error)); } if (_data.input_frames_used == 0) { throw EssentiaException("Resample: Internal consumption problem while resampling"); } } EXEC_DEBUG("input frames:" << _data.input_frames_used); EXEC_DEBUG("produced:" << _data.output_frames_gen); _delay += (Real)_data.input_frames_used*_data.src_ratio - (Real)_data.output_frames_gen; assert((int)resampled.size() >= _data.output_frames_gen); assert((int)signal.size() >= _data.input_frames_used); _signal.setReleaseSize(_data.input_frames_used); _resampled.setReleaseSize(_data.output_frames_gen); releaseData(); EXEC_DEBUG("released"); return OK; }
AlgorithmStatus Trimmer::process() { EXEC_DEBUG("process()"); if ((_consumed < _startIndex) && (_consumed + _preferredSize > _startIndex)) { _input.setAcquireSize(_startIndex - _consumed); _input.setReleaseSize(_startIndex - _consumed); } if (_consumed == _startIndex) { _input.setAcquireSize(_preferredSize); _input.setReleaseSize(_preferredSize); } AlgorithmStatus status = acquireData(); if (status != OK) { // if status == NO_OUTPUT, we should temporarily stop the framecutter, // return from this function so its dependencies can process the frames, // and reschedule the framecutter to run when all this is done. if (status == NO_OUTPUT) { EXEC_DEBUG("no more output available for trimmer; mark it for rescheduling and return"); //_reschedule = true; return NO_OUTPUT; // if the buffer is full, we need to have produced something! } // if shouldStop is true, that means there is no more audio, so we need // to take what's left to fill in the output buffer if (!shouldStop()) return NO_INPUT; int available = input("signal").available(); EXEC_DEBUG("Frame could not be fully acquired. Next frame will be incomplete"); EXEC_DEBUG("There are " << available << " available tokens"); if (available == 0) { shouldStop(true); return NO_INPUT; } _input.setAcquireSize(available); _input.setReleaseSize(available); _output.setAcquireSize(available); _output.setReleaseSize(available); _preferredSize = available; return process(); } EXEC_DEBUG("data acquired"); // get the audio input and copy it to the output const vector<Real>& input = _input.tokens(); vector<Real>& output = _output.tokens(); if (_consumed >= _startIndex && _consumed < _endIndex) { assert(input.size() == output.size()); int howMany = min((long long)input.size(), _endIndex - _consumed); fastcopy(output.begin(), input.begin(), howMany); _output.setReleaseSize(howMany); } else { _output.setReleaseSize(0); } EXEC_DEBUG("produced frame"); _consumed += _input.releaseSize(); // optimization: we should also tell the parent (most of the time an // audio loader) to also stop, to avoid decoding an entire mp3 when only // 10 seconds are needed if (_consumed >= _endIndex) { // FIXME: does still still work with the new composites? shouldStop(true); const_cast<SourceBase*>(_input.source())->parent()->shouldStop(true); } EXEC_DEBUG("releasing"); releaseData(); EXEC_DEBUG("released"); return OK; }
AlgorithmStatus Slicer::process() { EXEC_DEBUG("process()"); // 10 first, consume and release tokens until we reach the start of the first slice // 20 produce the first slice, push it, and remove it from the list of slices to be processed // 30 goto 10 // in case we already processed all slices, just gobble up data if (_sliceIdx == int(_slices.size())) { bool ok = _input.acquire(defaultPreferredSize); if (!ok) return NO_INPUT; // TODO: make a special case for end of stream? _input.release(defaultPreferredSize); return OK; } int startIndex = _slices[_sliceIdx].first; int endIndex = _slices[_sliceIdx].second; // arriving there, only consume the tokens left before we reach the beginning of the slice if ((_consumed < startIndex) && (_consumed + _input.acquireSize() > startIndex)) { _input.setAcquireSize(startIndex - _consumed); _input.setReleaseSize(startIndex - _consumed); } // we're at the beginning of a slice, grab it entirely at once if (_consumed == startIndex) { _input.setAcquireSize(endIndex - startIndex); } AlgorithmStatus status = acquireData(); if (status != OK) { // FIXME: what does this return do here, without a comment explaining why we now skip everything after it??? return status; // if shouldStop is true, that means there is no more audio, so we need to stop if (!shouldStop()) return status; EXEC_DEBUG("Slice could not be fully acquired. Creating a partial slice to " "the end of the token stream."); EXEC_DEBUG("There are " << _input.available() << " available tokens left."); // Since there is no more tokens to consume, the last slice will be // partial (not to the end of endIndex) if (_input.available() == 0) return NO_INPUT; _input.setAcquireSize(_input.available()); _input.setReleaseSize(_input.available()); status = acquireData(); // If the last of the tokens could not be acquired, abort if (status != OK) return status; } int acquired = _input.acquireSize(); EXEC_DEBUG("data acquired (in: " << acquired << ")"); // are we dropping the tokens, or are we at the beginning of a slice, in which // case we need to copy it if (_consumed != startIndex) { // we're still dropping tokens to arrive to a slice _input.release(acquired); _consumed += acquired; return OK; } // we are copying a slice, get the audio input and copy it to the output const vector<Real>& input = _input.tokens(); vector<Real>& output = _output.firstToken(); assert((int)input.size() == _input.acquireSize()); output.resize(input.size()); fastcopy(output.begin(), input.begin(), (int)output.size()); EXEC_DEBUG("produced frame"); // set release size in function of next slice to get _sliceIdx++; int toRelease = acquired; // if next slice is very close, be careful not to release too many tokens if (_sliceIdx < (int)_slices.size()) { toRelease = min(toRelease, _slices[_sliceIdx].first - _consumed); } _input.setReleaseSize(toRelease); EXEC_DEBUG("releasing"); releaseData(); _consumed += _input.releaseSize(); EXEC_DEBUG("released"); // reset acquireSize to its default value _input.setAcquireSize(defaultPreferredSize); return OK; }