//============================================================================== void LoopingAudioSource::setLoopTimes (double startTime, double endTime) { jassert (endTime > startTime); // end time has to be after start! { const ScopedLock sl (loopPosLock); loopStartTime = startTime; loopEndTime = endTime; loopStartSample = (int64) (startTime * currentSampleRate); loopEndSample = (int64) (endTime * currentSampleRate); } // need to update read position based on new limits setNextReadPosition (getNextReadPosition()); }
void AudioTransportSource::setPosition (double newPosition) { if (sampleRate > 0.0) setNextReadPosition ((int64) (newPosition * sampleRate)); }
void AudioTransportSourceMod::setPosition (double newPosition) { if (sampleRate > 0.0) setNextReadPosition (roundToInt (newPosition * sampleRate)); }
void CDPlayer::sliderValueChanged(Slider* sliderThatWasMoved) { // Possible loss of precision is acceptable for very large values because user can't select specific value that precise. setNextReadPosition(static_cast<int64>(sliderThatWasMoved->getValue())); }
CDPlayer::CDPlayer(MixerComponent* mixer, OutputChannelNames* outputChannelNames, SoloBusSettings& soloBusSettings, TimeSliceThread& thread, PluginLoader& pluginLoader, float gain, bool solo, bool mute) : m_mixer(mixer) , m_outputChannelNames(outputChannelNames) , m_soloBusSettings(soloBusSettings) , m_gain(1.0f) , m_solo(solo) , m_soloMute(false) , m_mute(mute) , m_pluginLoader(pluginLoader) , m_thread(thread) , m_playButton("Play") , m_pauseButton("Pause") , m_stopButton("Stop") , m_skipBackwardButton("Skip Backward") , m_skipForwardButton("Skip Forward") , m_configureButton("Configure") #if JUCE_WINDOWS , m_ejectButton("Eject") #endif , m_remappingAudioSource(&m_transportSource, soloBusSettings, false) , m_digitalDisplay(String::empty, "00:00:00") , m_slider(Slider::LinearHorizontal, Slider::NoTextBox) , m_tracksTable([&](int trackIndex) { setNextReadPosition(m_reader->getPositionOfTrackStart(trackIndex)); m_transportSource.start(); startTimer(50); m_pluginLoader.playingStateChanged(getName().toRawUTF8(), true); }) { // play button Image normalImage = ImageFileFormat::loadFrom(BinaryData::mediaplaybackstart_png, BinaryData::mediaplaybackstart_pngSize); m_playButton.addListener(this); m_playButton.setEnabled(false); m_playButton.setImages(true, true, true, normalImage, 0.7f, Colours::transparentBlack, normalImage, 1.0f, Colours::transparentBlack, normalImage, 1.0f, Colours::pink.withAlpha(0.8f), 0.0f); addAndMakeVisible(m_playButton); // pause button m_pauseButton.addListener(this); m_pauseButton.setEnabled(false); normalImage = ImageFileFormat::loadFrom(BinaryData::mediaplaybackpause_png, BinaryData::mediaplaybackpause_pngSize); m_pauseButton.setImages(true, true, true, normalImage, 0.7f, Colours::transparentBlack, normalImage, 1.0f, Colours::transparentBlack, normalImage, 1.0f, Colours::pink.withAlpha(0.8f), 0.0f); addAndMakeVisible(m_pauseButton); // stop button m_stopButton.addListener(this); m_stopButton.setEnabled(false); normalImage = ImageFileFormat::loadFrom(BinaryData::mediaplaybackstop_png, BinaryData::mediaplaybackstop_pngSize); m_stopButton.setImages(true, true, true, normalImage, 0.7f, Colours::transparentBlack, normalImage, 1.0f, Colours::transparentBlack, normalImage, 1.0f, Colours::pink.withAlpha(0.8f), 0.0f); addAndMakeVisible(m_stopButton); // skip backward button m_skipBackwardButton.addListener(this); m_skipBackwardButton.setEnabled(false); normalImage = ImageFileFormat::loadFrom(BinaryData::mediaskipbackward_png, BinaryData::mediaskipbackward_pngSize); m_skipBackwardButton.setImages(true, true, true, normalImage, 0.7f, Colours::transparentBlack, normalImage, 1.0f, Colours::transparentBlack, normalImage, 1.0f, Colours::pink.withAlpha(0.8f), 0.0f); addAndMakeVisible(m_skipBackwardButton); // skip forward button m_skipForwardButton.addListener(this); m_skipForwardButton.setEnabled(false); normalImage = ImageFileFormat::loadFrom(BinaryData::mediaskipforward_png, BinaryData::mediaskipforward_pngSize); m_skipForwardButton.setImages(true, true, true, normalImage, 0.7f, Colours::transparentBlack, normalImage, 1.0f, Colours::transparentBlack, normalImage, 1.0f, Colours::pink.withAlpha(0.8f), 0.0f); addAndMakeVisible(m_skipForwardButton); #if JUCE_WINDOWS // eject button m_ejectButton.addListener(this); m_ejectButton.setEnabled(false); normalImage = ImageFileFormat::loadFrom(BinaryData::mediaeject_png, BinaryData::mediaeject_pngSize); m_ejectButton.setImages(true, true, true, normalImage, 0.7f, Colours::transparentBlack, normalImage, 1.0f, Colours::transparentBlack, normalImage, 1.0f, Colours::pink.withAlpha(0.8f), 0.0f); addAndMakeVisible(m_ejectButton); #endif // configuration button normalImage = ImageFileFormat::loadFrom(BinaryData::configure_png, BinaryData::configure_pngSize); m_configureButton.setImages(true, true, true, normalImage, 0.7f, Colours::transparentBlack, normalImage, 1.0f, Colours::transparentBlack, normalImage, 1.0f, Colours::pink.withAlpha(0.8f), 0.0f); addAndMakeVisible(m_configureButton); m_configureButton.addMouseListener(this, false); // playback time display addAndMakeVisible(m_digitalDisplay); // CD combo box m_availableCDsComboBox.addListener(this); addAndMakeVisible(m_availableCDsComboBox); addAndMakeVisible(m_slider); m_slider.addListener(this); m_slider.setEnabled(false); // playlist addAndMakeVisible(m_tracksTable); m_tracksTable.setColour(ListBox::outlineColourId, Colours::grey); m_tracksTable.setOutlineThickness(1); m_remappingAudioSource.setNumberOfChannelsToProduce(outputChannelNames->getNumberOfChannels()); m_remappingAudioSource.setOutputChannelMapping(0, 0); m_remappingAudioSource.setOutputChannelMapping(1, 1); m_mixer->getMixerAudioSource().addInputSource(&m_remappingAudioSource, false); mixer->registerPlayer(this); setGain(gain); addKeyListener(this); setBounds(0, 0, 600, 300); m_soloBusSettings.addListener(this); }
void LoopMachine::getNextAudioBlockFixedBpm(const AudioSourceChannelInfo& bufferToFill) { auto& transport = audioEngine.getTransport(); bool mainTransportPlaying = transport.isPlaying(); if (fixedBpmTransport.isPlaying() != mainTransportPlaying) { if (mainTransportPlaying) fixedBpmTransport.play(); else fixedBpmTransport.stop(); } fixedBpmTransport.updateTransport(bufferToFill.numSamples); bufferToFill.clearActiveBufferRegion(); if (fixedBpmTransport.isPlaying()) { float frameStartTicks = fixedBpmTransport.getFrameStartTicks(); float frameEndTicks = fixedBpmTransport.getFrameEndTicks(); float nextTick = (float) ((int)frameStartTicks + 1); float fadeLengthTicks = fixedBpmTransport.millisToTicks(FADE_TIME_MS); float fadeStartTicks = nextTick - fadeLengthTicks; float fadeEndTicks = nextTick; if (frameStartTicks < fadeStartTicks && frameEndTicks >= fadeStartTicks) drainRingBuffer(); // std::cout << "MPD: CPP: LoopMachine::getNextAudioBlock: reality check! " << ((int)nextTick/4) << std::endl; for (int groupIx = 0; groupIx < groupIxToLoopInfo.size(); groupIx++) { int state = audioState[groupIx]; int prevState = prevAudioState[groupIx]; if (state == LOOP_INACTIVE && prevState == LOOP_INACTIVE) { // we were doing nothing last period, and we're still doing nothing: do nothing } else if (state == LOOP_INACTIVE && prevState != LOOP_INACTIVE) { // for this loop group, we are fading out: going from an active loop to silence. processFadeOut(groupIx, prevState, frameStartTicks, frameEndTicks, fadeStartTicks, fadeEndTicks, bufferToFill); } else if (!wasPlaying || (state != LOOP_INACTIVE && prevState == LOOP_INACTIVE)) { // for this loop group, we are fading in: going from silence to signal. setReaderPos(groupIx, state, fadeStartTicks, frameStartTicks); processFadeIn(groupIx, state, frameStartTicks, frameEndTicks, fadeStartTicks, fadeEndTicks, bufferToFill); } else if (prevState != state) { // for this loop group, the loop being played has switched: do a crossfade processFadeOut(groupIx, prevState, frameStartTicks, frameEndTicks, fadeStartTicks, fadeEndTicks, bufferToFill); setReaderPos(groupIx, state, fadeStartTicks, frameStartTicks); processFadeIn(groupIx, state, frameStartTicks, frameEndTicks, fadeStartTicks, fadeEndTicks, bufferToFill); } else { // we're playing the same thing as in the last period. if (!wasPlaying) { auto src = (*groupIxToLoopInfo[groupIx])[state]; src->reader->setNextReadPosition(0); } processBlock(groupIx, state, 0, bufferToFill.numSamples, bufferToFill); } } if (frameStartTicks < fadeEndTicks && frameEndTicks >= fadeEndTicks) { bool changes = false; for (int groupIx = 0; groupIx < groupIxToLoopInfo.size(); groupIx++) { int state = audioState[groupIx]; if (state != LOOP_INACTIVE) { auto type = (*groupIxToLoopInfo[groupIx])[state]->type; auto src = (*groupIxToLoopInfo[groupIx])[state]->reader; if (type == LoopType::ONE_SHOT && audioState[groupIx] != LOOP_INACTIVE && src != nullptr && src->getNextReadPosition() >= src->getTotalLength()) { // (groupIx, prevState) is done playing. // now we need to plop a message in the ring buffer audioState[groupIx] = LOOP_INACTIVE; userState[groupIx] = LOOP_INACTIVE; int ix = ++endReserveIx & RINGBUF_SIZE_M1; // == ++reserveIx % RINGBUF_SIZE endringbuf[ix][0] = groupIx; endringbuf[ix][1] = state; endCommitIx++; changes = true; src->setNextReadPosition(0); // std::cout << "MPD: handling messaages audio thread" << std::endl; } } } if (changes) sendChangeMessage(); std::memcpy(prevAudioState, audioState, sizeof(audioState)); wasPlaying = true; } // bufferToFill.buffer->applyGain(0, 0, bufferToFill.numSamples, 0.5); // bufferToFill.buffer->applyGain(1, 0, bufferToFill.numSamples, 0.5); // wasPlaying = true; } if (wasPlaying && !fixedBpmTransport.isPlaying()) wasPlaying = false; }