void RecorderSlaveBlock::eachFrame() { if (m_recording) { // recording if (m_linkNode->getValue() < LuminosusConstants::triggerThreshold) { stopRecording(); return; } double value = m_inputNode->getValue(); m_data.append(value); m_outputNode->setValue(value); emit dataChanged(); return; } if (m_playing && !m_data.isEmpty()) { // playing double value = m_data[m_playbackPosition % m_data.size()]; m_outputNode->setValue(value); // either progress frame or stop: if (m_playbackPosition + 1 >= m_data.size() || m_linkNode->getValue() < LuminosusConstants::triggerThreshold) { m_playing.setValue(false); m_playbackPosition = 0; emit playbackPositionChanged(); } else { m_playbackPosition = (m_playbackPosition + 1) % m_data.size(); emit playbackPositionChanged(); } } }
SampleTCO::SampleTCO( Track * _track ) : TrackContentObject( _track ), m_sampleBuffer( new SampleBuffer ), m_isPlaying( false ) { saveJournallingState( false ); setSampleFile( "" ); restoreJournallingState(); // we need to receive bpm-change-events, because then we have to // change length of this TCO connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ), this, SLOT( updateLength() ), Qt::DirectConnection ); connect( Engine::getSong(), SIGNAL( timeSignatureChanged( int,int ) ), this, SLOT( updateLength() ) ); //care about positionmarker TimeLineWidget * timeLine = Engine::getSong()->getPlayPos( Engine::getSong()->Mode_PlaySong ).m_timeLine; if( timeLine ) { connect( timeLine, SIGNAL( positionMarkerMoved() ), this, SLOT( playbackPositionChanged() ) ); } //playbutton clicked or space key / on Export Song set isPlaying to false connect( Engine::getSong(), SIGNAL( playbackStateChanged() ), this, SLOT( playbackPositionChanged() ), Qt::DirectConnection ); //care about loops connect( Engine::getSong(), SIGNAL( updateSampleTracks() ), this, SLOT( playbackPositionChanged() ), Qt::DirectConnection ); //care about mute TCOs connect( this, SIGNAL( dataChanged() ), this, SLOT( playbackPositionChanged() ) ); //care about mute track connect( getTrack()->getMutedModel(), SIGNAL( dataChanged() ), this, SLOT( playbackPositionChanged() ), Qt::DirectConnection ); //care about TCO position connect( this, SIGNAL( positionChanged() ), this, SLOT( updateTrackTcos() ) ); switch( getTrack()->trackContainer()->type() ) { case TrackContainer::BBContainer: setAutoResize( true ); break; case TrackContainer::SongContainer: // move down default: setAutoResize( false ); break; } updateTrackTcos(); }
LfoController::LfoController( Model * _parent ) : Controller( Controller::LfoController, _parent, tr( "LFO Controller" ) ), m_baseModel( 0.5, 0.0, 1.0, 0.001, this, tr( "Base value" ) ), m_speedModel( 2.0, 0.01, 20.0, 0.0001, 20000.0, this, tr( "Oscillator speed" ) ), m_amountModel( 1.0, -1.0, 1.0, 0.005, this, tr( "Oscillator amount" ) ), m_phaseModel( 0.0, 0.0, 360.0, 4.0, this, tr( "Oscillator phase" ) ), m_waveModel( Oscillator::SineWave, 0, Oscillator::NumWaveShapes, this, tr( "Oscillator waveform" ) ), m_multiplierModel( 0, 0, 2, this, tr( "Frequency Multiplier" ) ), m_duration( 1000 ), m_phaseOffset( 0 ), m_currentPhase( 0 ), m_sampleFunction( &Oscillator::sinSample ), m_userDefSampleBuffer( new SampleBuffer ) { setSampleExact( true ); connect( &m_waveModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleFunction() ) ); connect( &m_speedModel, SIGNAL( dataChanged() ), this, SLOT( updateDuration() ) ); connect( &m_multiplierModel, SIGNAL( dataChanged() ), this, SLOT( updateDuration() ) ); connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateDuration() ) ); connect( engine::getSong(), SIGNAL( playbackStateChanged() ), this, SLOT( updatePhase() ) ); connect( engine::getSong(), SIGNAL( playbackPositionChanged() ), this, SLOT( updatePhase() ) ); updateDuration(); }
void SampleTCO::setSampleFile( const QString & _sf ) { m_sampleBuffer->setAudioFile( _sf ); updateLength(); emit sampleChanged(); emit playbackPositionChanged(); }
void SampleTCO::setSampleFile( const QString & _sf ) { m_sampleBuffer->setAudioFile( _sf ); setStartTimeOffset( 0 ); changeLength( (int) ( m_sampleBuffer->frames() / Engine::framesPerTick() ) ); emit sampleChanged(); emit playbackPositionChanged(); }
void song::setPlayPos( tick_t _ticks, PlayModes _play_mode ) { m_elapsedTicks += m_playPos[_play_mode].getTicks() - _ticks; m_elapsedMilliSeconds += (((( _ticks - m_playPos[_play_mode].getTicks()))*60*1000/48)/getTempo()); m_playPos[_play_mode].setTicks( _ticks ); m_playPos[_play_mode].setCurrentFrame( 0.0f ); // send a signal if playposition changes during playback if( isPlaying() ) { emit playbackPositionChanged(); } }
void Song::setPlayPos( tick_t ticks, PlayModes playMode ) { tick_t ticksFromPlayMode = m_playPos[playMode].getTicks(); m_elapsedTicks += ticksFromPlayMode - ticks; m_elapsedMilliSeconds += MidiTime::ticksToMilliseconds( ticks - ticksFromPlayMode, getTempo() ); m_playPos[playMode].setTicks( ticks ); m_playPos[playMode].setCurrentFrame( 0.0f ); // send a signal if playposition changes during playback if( isPlaying() ) { emit playbackPositionChanged(); emit updateSampleTracks(); } }
AudioPlaybackBlock::AudioPlaybackBlock(MainController* controller, QString uid) : BlockBase(controller, uid) , m_playNode(nullptr) , m_pauseNode(nullptr) , m_toggleNode(nullptr) , m_activeNode(nullptr) , m_endNode(nullptr) , m_positionNode(nullptr) , m_filePath("") , m_lastPlayNodeValue(0.0) , m_lastPauseNodeValue(0.0) , m_lastToggleNodeValue(0.0) , m_alwaysStartAtBegin(false) , m_loop(false) , m_toggleMode(true) , m_player(this) { m_widthIsResizable = true; m_playNode = createInputNode("playNode"); m_pauseNode = createInputNode("pauseNode"); m_toggleNode = createInputNode("toggleNode"); connect(m_playNode, SIGNAL(dataChanged()), this, SLOT(onPlayNodeValueChanged())); connect(m_pauseNode, SIGNAL(dataChanged()), this, SLOT(onPauseNodeValueChanged())); connect(m_toggleNode, SIGNAL(dataChanged()), this, SLOT(onToggleNodeValueChanged())); m_activeNode = createOutputNode("activeNode"); m_endNode = createOutputNode("endNode"); m_positionNode = createOutputNode("positionNode"); // setup Timer to be able to send a short pulse when end of file is reached: m_endPulseTimer.setSingleShot(true); m_endPulseTimer.setInterval(100); connect(&m_endPulseTimer, SIGNAL(timeout()), this, SLOT(onEndPulseTimeout())); connect(&m_player, SIGNAL(endOfFile()), this, SLOT(onEndOfFile())); connect(&m_player, SIGNAL(isPlayingChanged()), this, SIGNAL(isPlayingChanged())); connect(&m_player, SIGNAL(isPlayingChanged()), this, SLOT(onIsPlayingChanged())); connect(&m_player, SIGNAL(positionChanged()), this, SIGNAL(playbackPositionChanged())); connect(&m_player, SIGNAL(positionChanged()), this, SLOT(onPlaybackPositionChanged())); connect(&m_player, SIGNAL(lengthChanged()), this, SIGNAL(lengthChanged())); connect(&m_waveform, SIGNAL(pointsChanged()), this, SIGNAL(waveformChanged())); connect(&m_waveform, SIGNAL(availableChanged()), this, SIGNAL(waveformChanged())); }
void SampleTCO::setSampleFile( const QString & _sf ) { int length; if ( _sf.isEmpty() ) { //When creating an empty sample pattern make it a bar long float nom = Engine::getSong()->getTimeSigModel().getNumerator(); float den = Engine::getSong()->getTimeSigModel().getDenominator(); length = DefaultTicksPerTact * ( nom / den ); } else { //Otherwise set it to the sample's length m_sampleBuffer->setAudioFile( _sf ); length = sampleLength(); } changeLength(length); setStartTimeOffset( 0 ); emit sampleChanged(); emit playbackPositionChanged(); }
void MidiPlayer::run() { // Workaround to fix errors with the Microsoft GS Wavetable Synth on // Windows 10 - see http://stackoverflow.com/a/32553208/586978 #ifdef _WIN32 CoInitializeEx(nullptr, COINIT_MULTITHREADED); BOOST_SCOPE_EXIT(this_) { CoUninitialize(); } BOOST_SCOPE_EXIT_END #endif boost::signals2::scoped_connection connection( mySettingsManager.subscribeToChanges([&]() { auto settings = mySettingsManager.getReadHandle(); myMetronomeEnabled = settings->get(Settings::MetronomeEnabled); })); setIsPlaying(true); MidiFile::LoadOptions options; options.myEnableMetronome = true; options.myRecordPositionChanges = true; // Load MIDI settings. int api; int port; { auto settings = mySettingsManager.getReadHandle(); myMetronomeEnabled = settings->get(Settings::MetronomeEnabled); api = settings->get(Settings::MidiApi); port = settings->get(Settings::MidiPort); options.myMetronomePreset = settings->get(Settings::MetronomePreset) + Midi::MIDI_PERCUSSION_PRESET_OFFSET; options.myStrongAccentVel = settings->get(Settings::MetronomeStrongAccent); options.myWeakAccentVel = settings->get(Settings::MetronomeWeakAccent); options.myVibratoStrength = settings->get(Settings::MidiVibratoLevel); options.myWideVibratoStrength = settings->get(Settings::MidiWideVibratoLevel); } MidiFile file; file.load(myScore, options); const int ticks_per_beat = file.getTicksPerBeat(); // Merge the MIDI evvents for each track. MidiEventList events; for (MidiEventList &track : file.getTracks()) { track.convertToAbsoluteTicks(); events.concat(track); } // TODO - since each track is already sorted, an n-way merge should be faster. std::stable_sort(events.begin(), events.end()); events.convertToDeltaTicks(); // Initialize RtMidi and set the port. MidiOutputDevice device; if (!device.initialize(api, port)) { emit error(tr("Error initializing MIDI output device.")); return; } bool started = false; int beat_duration = Midi::BEAT_DURATION_120_BPM; const SystemLocation start_location(myStartLocation.getSystemIndex(), myStartLocation.getPositionIndex()); SystemLocation current_location = start_location; for (auto event = events.begin(); event != events.end(); ++event) { if (!isPlaying()) break; if (event->isTempoChange()) beat_duration = event->getTempo(); // Skip events before the start location, except for events such as // instrument changes. Tempo changes are tracked above. if (!started) { if (event->getLocation() < start_location) { if (event->isProgramChange()) device.sendMessage(event->getData()); continue; } else { performCountIn(device, event->getLocation(), beat_duration); started = true; } } const int delta = event->getTicks(); assert(delta >= 0); const int duration_us = boost::rational_cast<int>( boost::rational<int>(delta, ticks_per_beat) * beat_duration); usleep(duration_us * (100.0 / myPlaybackSpeed)); // Don't play metronome events if the metronome is disabled. if (event->isNoteOnOff() && event->getChannel() == METRONOME_CHANNEL && !myMetronomeEnabled) { continue; } device.sendMessage(event->getData()); // Notify listeners of the current playback position. if (event->getLocation() != current_location) { const SystemLocation &new_location = event->getLocation(); // Don't move backwards unless a repeat occurred. if (new_location < current_location && !event->isPositionChange()) continue; if (new_location.getSystem() != current_location.getSystem()) emit playbackSystemChanged(new_location.getSystem()); emit playbackPositionChanged(new_location.getPosition()); current_location = new_location; } } }