diff --git a/ChangeLog b/ChangeLog index 5905412db..d96ed66b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,11 @@ - switching between note edit modes is more clear with label text and a right click menu - note volume bars are painted blue if selected + - dragging around a note in the piano roll makes the correct volume + and panning noises + + * include/panning.h: + added panningToMidi function to easily convert panning to a midi value 2008-12-14 Tobias Doerffel diff --git a/TODO b/TODO index 6c4a625d7..c9988fb98 100644 --- a/TODO +++ b/TODO @@ -52,7 +52,6 @@ - add FLAC as export-format? Andrew Kelley's todo: -- when you click on a note in the piano roll, it plays the note, but not the correct panning - fix ctrl+mousewheel zooming in - if you press both controls at the same time, the piano roll gets stuck in selection mode - change my modifier code to use mainwindows modifier info @@ -65,6 +64,7 @@ Andrew Kelley's todo: * look through FL Studio's tools and implement some of them - when looking at a piano roll, if the song is playing that pattern, move the position ticker to where it should be - double-click in note edit area to clear selection (assuming the intent of editing all notes) +- when setting a new note, set panning and volume to that of last note - recording automation - make knobs easier to tune (less sensitive) diff --git a/include/panning.h b/include/panning.h index 07dfd94d3..ea656f562 100644 --- a/include/panning.h +++ b/include/panning.h @@ -30,6 +30,7 @@ #include "volume.h" #include "templates.h" #include "panning_constants.h" +#include "midi.h" inline stereoVolumeVector panningToVolumeVector( panning _p, float _scale = 1.0f ) @@ -40,4 +41,12 @@ inline stereoVolumeVector panningToVolumeVector( panning _p, return v; } +inline Sint16 panningToMidi( panning _p ) +{ + return MidiMinPanning + + ( (float)( _p - PanningLeft ) ) / + ( (float)( PanningRight - PanningLeft ) ) * + ( (float)( MidiMaxPanning - MidiMinPanning ) ); +} + #endif diff --git a/include/piano_roll.h b/include/piano_roll.h index 1775c0993..5c30405f0 100644 --- a/include/piano_roll.h +++ b/include/piano_roll.h @@ -182,6 +182,8 @@ private: void shiftSemiTone(int amount); bool isSelection() const; void testPlayNote( note * n ); + void testPlayKey( int _key, int _vol, int _pan ); + void pauseTestNotes( bool _pause = true ); inline int noteEditTop() const; inline int keyAreaBottom() const; diff --git a/src/gui/piano_roll.cpp b/src/gui/piano_roll.cpp index a393dd548..bf6ea383f 100644 --- a/src/gui/piano_roll.cpp +++ b/src/gui/piano_roll.cpp @@ -1515,11 +1515,68 @@ void pianoRoll::testPlayNote( note * n ) m_pattern->getInstrumentTrack()->processInEvent( midiEvent( MidiNoteOn, 0, n->key(), n->getVolume() * 127 / 100 ), midiTime() ); - + + midiEvent evt( MidiMetaEvent, 0, n->key(), + panningToMidi( n->getPanning() ) ); + + evt.m_metaEvent = MidiNotePanning; + m_pattern->getInstrumentTrack()->processInEvent( + evt, midiTime() ); + m_pattern->getInstrumentTrack()->processInEvent(evt, midiTime() ); + } } +void pianoRoll::pauseTestNotes( bool _pause ) +{ + const noteVector & notes = m_pattern->notes(); + noteVector::const_iterator it = notes.begin(); + while( it != notes.end() ) + { + if( ( *it )->isPlaying() ) + { + if( _pause ) + { + // stop note + m_pattern->getInstrumentTrack()->processInEvent( + midiEvent( MidiNoteOff, 0, + ( *it )->key(), 0 ), midiTime() ); + } + else + { + // start note + ( *it )->setIsPlaying( false ); + testPlayNote( *it ); + } + } + + ++it; + } +} + + +void pianoRoll::testPlayKey( int _key, int _vol, int _pan ) +{ + // turn off old key + m_pattern->getInstrumentTrack()->processInEvent( + midiEvent( MidiNoteOff, 0, m_lastKey, 0 ), midiTime() ); + + // remember which one we're playing + m_lastKey = _key; + + // play new key + m_pattern->getInstrumentTrack()->processInEvent( + midiEvent( MidiNoteOn, 0, _key, _vol ), midiTime() ); + + // set panning of newly played key + midiEvent evt( MidiMetaEvent, 0, _key, _pan ); + evt.m_metaEvent = MidiNotePanning; + m_pattern->getInstrumentTrack()->processInEvent( evt, midiTime() ); + +} + + void pianoRoll::computeSelectedNotes(bool shift) { @@ -1713,36 +1770,19 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) int key_num = getKey( _me->y() ); int x = _me->x(); - // is the calculated key different from current key? - // (could be the user just moved the cursor one pixel up/down - // but is still on the same key) - if( key_num != m_lastKey && edit_note == false && - _me->buttons() & Qt::LeftButton && - ( m_action == ActionMoveNote || - ( x < WHITE_KEY_WIDTH && m_action == ActionNone ) ) ) - { - m_pattern->getInstrumentTrack()->processInEvent( - midiEvent( MidiNoteOff, 0, m_lastKey, 0 ), - midiTime() ); - if( _me->buttons() & Qt::LeftButton ) - { - m_lastKey = key_num; - - int v = DefaultVolume * 127 / 100; - if( x < WHITE_KEY_WIDTH ) - { - v = ( (float) x ) / ( (float) WHITE_KEY_WIDTH ) * 127; - } - - m_pattern->getInstrumentTrack()->processInEvent( - midiEvent( MidiNoteOn, 0, key_num, v ), midiTime() ); - } - } - if( x < WHITE_KEY_WIDTH && m_action == ActionNone ) + // see if they clicked on the keyboard on the left + if( x < WHITE_KEY_WIDTH && m_action == ActionNone + && ! edit_note && key_num != m_lastKey + && _me->buttons() & Qt::LeftButton ) { + // clicked on a key, play the note + testPlayKey( key_num, + ( (float) x ) / ( (float) WHITE_KEY_WIDTH ) * 127, + 0 ); update(); return; } + x -= WHITE_KEY_WIDTH; if( _me->buttons() & Qt::LeftButton @@ -1750,7 +1790,20 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) && (m_action == ActionMoveNote || m_action == ActionResizeNote ) ) { // handle moving notes and resizing them + bool replay_note = key_num != m_lastKey + && m_action == ActionMoveNote; + + if( replay_note ) + { + pauseTestNotes(); + } + dragNotes(_me->x(), _me->y(), _me->modifiers() & Qt::AltModifier); + + if( replay_note && m_action == ActionMoveNote ) + { + pauseTestNotes( false ); + } } else if( ( edit_note == true || m_action == ActionChangeNoteProperty ) && _me->buttons() & Qt::LeftButton ) @@ -1759,7 +1812,7 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) // Change notes within a certain pixel range of where // the mouse cursor is - int pixel_range = 20; + int pixel_range = 14; // convert to ticks so that we can check which notes // are in the range @@ -1813,11 +1866,8 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me ) else if( m_noteEditMode == NoteEditPanning ) { ( *it )->setPanning( pan ); - midiEvent evt( MidiMetaEvent, 0, ( *it )->key(), - MidiMinPanning + - ( (float)( pan - PanningLeft ) ) / - ( (float)( PanningRight - PanningLeft ) ) * - ( (float)( MidiMaxPanning - MidiMinPanning ) ) ); + midiEvent evt( MidiMetaEvent, 0, + ( *it )->key(), panningToMidi( pan ) ); evt.m_metaEvent = MidiNotePanning; m_pattern->getInstrumentTrack()->processInEvent( evt, midiTime() );