diff --git a/ChangeLog b/ChangeLog index aadc6e6ef..258df8462 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2009-02-19 Tobias Doerffel + + * include/instrument_track.h: + * include/piano_roll.h: + * src/gui/piano_roll.cpp: + * src/gui/song_editor.cpp: + * src/tracks/instrument_track.cpp: + fixed various bugs regarding recording: + - once recording has been started, stop it as soon as playMode of song + changes or similiar things happen (closes #2486341) + - fixed broken record-accompany in most use-cases other than using + record-while-playing-song by also tracking NoteOn events and remember + current play position to use the correct note postitions on NoteOff + events (play position might have wrapped around in the meantime due + to looppoints or end of BB track) (closes #2486299, #2486203) + 2009-02-14 Tobias Doerffel * src/3rdparty/samplerate/samplerate.h: diff --git a/include/instrument_track.h b/include/instrument_track.h index e061a90e8..7b7fab9bf 100644 --- a/include/instrument_track.h +++ b/include/instrument_track.h @@ -2,7 +2,7 @@ * instrument_track.h - declaration of class instrumentTrack, a track + window * which holds an instrument-plugin * - * Copyright (c) 2004-2008 Tobias Doerffel + * Copyright (c) 2004-2009 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -185,7 +185,8 @@ public: signals: void instrumentChanged( void ); void newNote( void ); - void noteDone( const note & _n ); + void noteOn( const note & _n ); + void noteOff( const note & _n ); void nameChanged( void ); diff --git a/include/piano_roll.h b/include/piano_roll.h index a4fd75bc0..1da1d0a39 100644 --- a/include/piano_roll.h +++ b/include/piano_roll.h @@ -2,7 +2,7 @@ * piano_roll.h - declaration of class pianoRoll which is a window where you * can set and edit notes in an easy way * - * Copyright (c) 2004-2008 Tobias Doerffel + * Copyright (c) 2004-2009 Tobias Doerffel * Copyright (c) 2008 Andrew Kelley * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net @@ -34,6 +34,7 @@ #include "serializing_object.h" #include "note.h" #include "lmms_basics.h" +#include "song.h" class QPainter; @@ -56,6 +57,11 @@ class pianoRoll : public QWidget, public serializingObject public: void setCurrentPattern( pattern * _new_pattern ); + inline void stopRecording( void ) + { + m_recording = false; + } + inline bool isRecording( void ) const { return m_recording; @@ -71,6 +77,8 @@ public: return m_pattern != NULL; } + song::PlayModes desiredPlayModeForAccompany( void ) const; + int quantization( void ) const; @@ -110,7 +118,8 @@ protected slots: void recordAccompany( void ); void stop( void ); - void recordNote( const note & _n ); + void startRecordNote( const note & _n ); + void finishRecordNote( const note & _n ); void horScrolled( int _new_pos ); void verScrolled( int _new_pos ); @@ -241,6 +250,7 @@ private: midiTime m_currentPosition; bool m_recording; + QList m_recordingNotes; note * m_currentNote; actions m_action; diff --git a/src/gui/piano_roll.cpp b/src/gui/piano_roll.cpp index 212b83ddc..de145c23a 100644 --- a/src/gui/piano_roll.cpp +++ b/src/gui/piano_roll.cpp @@ -48,6 +48,7 @@ #include +#include "bb_track_container.h" #include "clipboard.h" #include "combobox.h" #include "debug.h" @@ -579,11 +580,12 @@ void pianoRoll::setCurrentPattern( pattern * _new_pattern ) // of start-notes and so on...) resizeEvent( NULL ); - // and now connect to noteDone()-signal of channel so that - // we receive note-off-events from it's midi-port for recording it connect( m_pattern->getInstrumentTrack(), - SIGNAL( noteDone( const note & ) ), - this, SLOT( recordNote( const note & ) ) ); + SIGNAL( noteOn( const note & ) ), + this, SLOT( startRecordNote( const note & ) ) ); + connect( m_pattern->getInstrumentTrack(), + SIGNAL( noteOff( const note & ) ), + this, SLOT( finishRecordNote( const note & ) ) ); setWindowTitle( tr( "Piano-Roll - %1" ).arg( m_pattern->name() ) ); @@ -2973,6 +2975,19 @@ int pianoRoll::getKey( int _y ) const +song::PlayModes pianoRoll::desiredPlayModeForAccompany( void ) const +{ + if( m_pattern->getTrack()->getTrackContainer() == + engine::getBBTrackContainer() ) + { + return song::Mode_PlayBB; + } + return song::Mode_PlaySong; +} + + + + void pianoRoll::play( void ) { if( validPattern() == false ) @@ -3041,7 +3056,7 @@ void pianoRoll::recordAccompany( void ) } m_recording = true; - + if( m_pattern->getTrack()->getTrackContainer() == engine::getSong() ) { engine::getSong()->play(); @@ -3068,17 +3083,49 @@ void pianoRoll::stop( void ) -void pianoRoll::recordNote( const note & _n ) +void pianoRoll::startRecordNote( const note & _n ) { - if( m_recording == true && validPattern() == true ) + if( m_recording == true && validPattern() == true && + engine::getSong()->isPlaying() && + ( engine::getSong()->playMode() == + desiredPlayModeForAccompany() || + engine::getSong()->playMode() == + song::Mode_PlayPattern ) ) { - note n( _n.length(), engine::getSong()->getPlayPos( - engine::getSong()->playMode() ) - _n.length(), + note n( 1, engine::getSong()->getPlayPos( + engine::getSong()->playMode() ), _n.key(), _n.getVolume(), _n.getPanning() ); - n.quantizeLength( quantization() ); - m_pattern->addNote( n ); - update(); - engine::getSong()->setModified(); + m_recordingNotes << n; + } +} + + + + +void pianoRoll::finishRecordNote( const note & _n ) +{ + if( m_recording == true && validPattern() == true && + engine::getSong()->isPlaying() && + ( engine::getSong()->playMode() == + desiredPlayModeForAccompany() || + engine::getSong()->playMode() == + song::Mode_PlayPattern ) ) + { + for( QList::Iterator it = m_recordingNotes.begin(); + it != m_recordingNotes.end(); ++it ) + { + if( it->key() == _n.key() ) + { + note n( _n.length(), it->pos(), + it->key(), it->getVolume(), + it->getPanning() ); + n.quantizeLength( quantization() ); + m_pattern->addNote( n ); + update(); + m_recordingNotes.erase( it ); + break; + } + } } } diff --git a/src/gui/song_editor.cpp b/src/gui/song_editor.cpp index 6542a4edf..15e15e6e3 100644 --- a/src/gui/song_editor.cpp +++ b/src/gui/song_editor.cpp @@ -3,7 +3,7 @@ /* * song_editor.cpp - basic window for song-editing * - * Copyright (c) 2004-2008 Tobias Doerffel + * Copyright (c) 2004-2009 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -51,6 +51,7 @@ #include "tooltip.h" #include "visualization_widget.h" #include "audio_device.h" +#include "piano_roll.h" @@ -414,6 +415,7 @@ void songEditor::scrolled( int _new_pos ) void songEditor::play( void ) { m_s->play(); + engine::getPianoRoll()->stopRecording(); if( m_s->playMode() == song::Mode_PlaySong ) { m_playButton->setIcon( embed::getIconPixmap( "pause" ) ); @@ -446,6 +448,7 @@ void songEditor::recordAccompany( void ) void songEditor::stop( void ) { m_s->stop(); + engine::getPianoRoll()->stopRecording(); m_playButton->setIcon( embed::getIconPixmap( "play" ) ); } diff --git a/src/tracks/instrument_track.cpp b/src/tracks/instrument_track.cpp index 32f191770..ef8c2a227 100644 --- a/src/tracks/instrument_track.cpp +++ b/src/tracks/instrument_track.cpp @@ -2,7 +2,7 @@ * instrument_track.cpp - implementation of instrument-track-class * (window + data-structures) * - * Copyright (c) 2004-2008 Tobias Doerffel + * Copyright (c) 2004-2009 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -248,6 +248,8 @@ void instrumentTrack::processInEvent( const midiEvent & _me, { m_notes[_me.key()] = nph; } + + emit noteOn( n ); } break; } @@ -259,7 +261,7 @@ void instrumentTrack::processInEvent( const midiEvent & _me, { // create dummy-note which has the same length // as the played note for sending it later - // to all slots connected to signal noteDone() + // to all slots connected to signal noteOff() // this is for example needed by piano-roll for // recording notes into a pattern note done_note( @@ -274,7 +276,7 @@ void instrumentTrack::processInEvent( const midiEvent & _me, n->noteOff(); m_notes[_me.key()] = NULL; - emit noteDone( done_note ); + emit noteOff( done_note ); } break; } @@ -463,7 +465,7 @@ void instrumentTrack::deleteNotePluginData( notePlayHandle * _n ) _n->getVolume(), _n->getPanning() ); _n->noteOff(); m_notes[_n->key()] = NULL; - emit noteDone( done_note ); + emit noteOff( done_note ); } }