void processAudio(AudioBuffer &buffer){ double rate = getSampleRate(); unsigned int sampleDelay = getSampleDelay(getRampedParameterValue(PARAMETER_A), rate); sampleDelay = min(sampleDelay, bufferSize); float feedback = getRampedParameterValue(PARAMETER_B); float bias = getBiasExponent(1 - getRampedParameterValue(PARAMETER_C)); float dryWetMix = getRampedParameterValue(PARAMETER_D); int size = buffer.getSize(); for(int ch = 0; ch<buffer.getChannels(); ++ch) { float* buf = buffer.getSamples(ch); for (int i=0; i<size; ++i) { float delaySample = circularBuffer[writeIdx]; float v = buf[i] + circularBuffer[writeIdx] * feedback; v = applyBias(v, bias); circularBuffer[writeIdx] = min(1, max(-1, v)); // Guard: hard range limits. buf[i] = linearBlend(buf[i], delaySample, dryWetMix); writeIdx = (++writeIdx) % sampleDelay; } } }
void BiasedDelay::processBlock(AudioSampleBuffer& buffer, int numInputChannels, int numOutputChannels, MidiBuffer& midiMessages){ // Atm we're assuming matching input/output channel counts jassert(numInputChannels==numOutputChannels); for (int channel=0; channel<numInputChannels; channel++) { processChannelBlock(buffer.getNumSamples(), buffer.getSampleData(channel), delayBuffer.getSampleData(channel), delayBufferIdx); } delayBufferIdx = (delayBufferIdx + buffer.getNumSamples()) % getSampleDelay(getParameterValue(PARAMETER_TIME)); }
void BiasedDelay::processChannelBlock(int size, float* buf, float* delayBuf, int delayBufIdx){ unsigned int sampleDelay = getSampleDelay(getParameterValue(PARAMETER_TIME)); float feedback = getParameterValue(PARAMETER_FEEDBACK); float bias = getBiasExponent(1 - getParameterValue(PARAMETER_BIAS)); float dryWetMix = getParameterValue(PARAMETER_DRYWET); for (int i=0; i<size; i++) { float delaySample = delayBuf[delayBufIdx]; float v = buf[i] + delaySample * feedback; v = applyBias(v, bias); delayBuf[delayBufIdx] = softLimit(v); // Guard: range limit. buf[i] = sigmoidXFade(buf[i], delaySample, dryWetMix); delayBufIdx = (++delayBufIdx) % sampleDelay; } }
uint32 ADLPlayer::pollMusic(bool first) { if (_timbres.empty() || !_songData || !_playPos || (_playPos >= (_songData + _songDataSize))) { end(); return 0; } // We'll ignore the first delay if (first) _playPos += (*_playPos & 0x80) ? 2 : 1; byte cmd = *_playPos++; // Song end marker if (cmd == 0xFF) { end(); return 0; } // Set the instrument that should be modified if (cmd == 0xFE) _modifyInstrument = *_playPos++; if (cmd >= 0xD0) { // Modify an instrument if (_modifyInstrument == 0xFF) warning("ADLPlayer: No instrument to modify"); else if (_modifyInstrument >= _timbres.size()) warning("ADLPlayer: Can't modify invalid instrument %d (%d)", _modifyInstrument, _timbres.size()); else _timbres[_modifyInstrument].params[_playPos[0]] = _playPos[1]; _playPos += 2; // If we currently have that instrument loaded, reload it for (int i = 0; i < kMaxVoiceCount; i++) if (_currentInstruments[i] == _modifyInstrument) setInstrument(i, _modifyInstrument); } else { // Voice command uint8 voice = cmd & 0x0F; uint8 note, volume; switch (cmd & 0xF0) { case 0x00: // Note on with volume note = *_playPos++; volume = *_playPos++; setVoiceVolume(voice, volume); noteOn(voice, note); break; case 0xA0: // Pitch bend bendVoicePitch(voice, ((uint16)*_playPos++) << 7); break; case 0xB0: // Set volume setVoiceVolume(voice, *_playPos++); break; case 0xC0: // Set instrument setInstrument(voice, *_playPos++); break; case 0x90: // Note on noteOn(voice, *_playPos++); break; case 0x80: // Note off noteOff(voice); break; default: warning("ADLPlayer: Unsupported command: 0x%02X. Stopping playback.", cmd); end(true); return 0; } } uint16 delay = *_playPos++; if (delay & 0x80) delay = ((delay & 3) << 8) | *_playPos++; return getSampleDelay(delay); }