editing note volume and hearing clicked on notes is implemented more cleanly, editing note volume only affects selected notes (or all notes if none selected), when "scribbling" note volumes, if there is a chord, it will play all 3 notes, rather than just the first one

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1909 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Andrew Kelley
2008-12-13 02:28:24 +00:00
parent d511b43088
commit b7f4f7be6d
6 changed files with 126 additions and 127 deletions

View File

@@ -1,3 +1,17 @@
2008-12-12 Andrew Kelley <superjoe30/at/gmail/dot/com>
* include/note.h:
* src/core/note.cpp:
* include/piano_roll.h:
* src/gui/piano_roll.cpp:
* TODO:
- editing note volume and hearing clicked on notes
is implemented more cleanly
- editing note volume only affects selected notes (or all notes if
none selected)
- when "scribbling" note volumes, if there is a chord, it will play all
3 notes, rather than just the first one
2008-12-11 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* include/automation_pattern.h:

22
TODO
View File

@@ -52,21 +52,23 @@
- add FLAC as export-format?
Andrew Kelley's todo:
- recording automation
- make knobs easier to tune (less sensitive)
- make the menu for a channel happen when you right click, instead of renaming, and make the midi input a top-level menu item
- add a "Set exact value" to a right clicked automation menu
- enable "auto detect" by default when you bring up the "connect to controller" window
- piano roll: make the note volume section have adjustable height
- add note panning ability to piano roll
- paint piano roll notes with a darker color based on how high volume the note is
- paint note volume blue if selected
- multiview button - show notes from every instrument in the current beat+bassline with different colors
- undo/redo for piano roll
- add a tools menu to piano roll
* put some of the tools on there that already have keyboard shortcuts (ctrl+up/down, shift+left/right)
* humanizing tool
* quick slice
* look through FL Studio's tools and implement some of them
- undo/redo for piano roll
- make copy/paste work beyond inside piano roll - it didn't work when I copied notes from one pattern and then opened another pattern and pasted.
- piano roll: make the note volume section have adjustable height
- add note panning ability to piano roll
- recording automation
- make knobs easier to tune (less sensitive)
- make the menu for a channel happen when you right click, instead of renaming, and make the midi input a top-level menu item
- add a "Set exact value" to a right clicked automation menu
- enable "auto detect" by default when you bring up the "connect to controller" window
- "paintbrush" tool for the song editor, to easily "paint" beat+basslines
- when you clone a track in the song editor, rename the track so that it doesn't have the same name (increment the number if necessary)

View File

@@ -91,6 +91,7 @@ public:
note( const note & _note );
virtual ~note();
// used by GUI
inline void setSelected( const bool _selected ){ m_selected = _selected; }
inline void setOldKey( const int _oldKey ){ m_oldKey = _oldKey; }
inline void setOldPos( const midiTime & _oldPos ){ m_oldPos = _oldPos; }
@@ -98,6 +99,11 @@ public:
{
m_oldLength = _oldLength;
}
inline void setIsPlaying( const bool _isPlaying )
{
m_isPlaying = _isPlaying;
}
void setLength( const midiTime & _length );
void setPos( const midiTime & _pos );
@@ -133,6 +139,11 @@ public:
{
return m_oldLength;
}
inline bool isPlaying( void ) const
{
return m_isPlaying;
}
inline midiTime endPos( void ) const
{
@@ -212,11 +223,13 @@ private:
ChangePosition
} ;*/
// for piano roll editing
bool m_selected;
int m_oldKey;
midiTime m_oldPos;
midiTime m_oldLength;
bool m_isPlaying;
int m_key;
volume m_volume;

View File

@@ -169,6 +169,7 @@ private:
void shiftPos(int amount);
void shiftSemiTone(int amount);
bool isSelection() const;
void testPlayNote( note * n );
void dragNotes( int x, int y, bool alt );

View File

@@ -44,6 +44,7 @@ note::note( const midiTime & _length, const midiTime & _pos,
m_oldKey( tLimit( _key, 0, NumKeys ) ),
m_oldPos( _pos ),
m_oldLength( _length ),
m_isPlaying( false ),
m_key( tLimit( _key, 0, NumKeys ) ),
m_volume( tLimit( _volume, MinVolume, MaxVolume ) ),
m_panning( tLimit( _panning, PanningLeft, PanningRight ) ),
@@ -72,6 +73,7 @@ note::note( const note & _note ) :
m_oldKey( _note.m_oldKey ),
m_oldPos( _note.m_oldPos ),
m_oldLength( _note.m_oldLength ),
m_isPlaying( _note.m_isPlaying ),
m_key( _note.m_key),
m_volume( _note.m_volume ),
m_panning( _note.m_panning ),

View File

@@ -1081,7 +1081,6 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
if( _me->y() > PR_TOP_MARGIN )
{
bool play_note = ! engine::getSong()->isPlaying();
volume vol = DefaultVolume;
bool edit_note = ( _me->y() > height() -
@@ -1169,10 +1168,9 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
m_currentNote = *it;
m_action = ActionChangeNoteVolume;
key_num = ( *it )->key();
}
else
{
play_note = false;
testPlayNote( *it );
}
}
// left button??
@@ -1280,17 +1278,12 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
// set resize-cursor
QCursor c( Qt::SizeHorCursor );
QApplication::setOverrideCursor( c );
play_note = false;
}
else
{
// otherwise move it
m_action = ActionMoveNote;
// set move-cursor
QCursor c( Qt::SizeAllCursor );
QApplication::setOverrideCursor( c );
@@ -1328,6 +1321,9 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
engine::getSongEditor()->update();
}
}
// play the note
testPlayNote( m_currentNote );
}
@@ -1346,7 +1342,6 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
{
// erase single note
m_mouseDownRight = true;
play_note = false;
if( it != notes.end() )
{
if( ( *it )->length() > 0 )
@@ -1372,36 +1367,35 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
m_selectedKeys = 1;
m_action = ActionSelectNotes;
play_note = false;
// call mousemove to fix glitch where selection
// appears in wrong spot on mousedown
mouseMoveEvent( _me );
}
else if( _me->button() == Qt::RightButton &&
m_editMode == ModeMove )
{
// when clicking right in select-move, we
// switch to draw-mode
m_drawButton->setChecked( true );
play_note = false;
}
update();
}
// was there an action where should be played the note?
if( play_note == true && m_recording == false )
{
m_lastKey = key_num;
m_pattern->getInstrumentTrack()->processInEvent(
midiEvent( MidiNoteOn, 0, key_num,
vol * 127 / 100 ),
midiTime() );
}
}
}
void pianoRoll::testPlayNote( note * n )
{
m_lastKey = n->key();
if(! n->isPlaying() && ! m_recording && ! engine::getSong()->isPlaying() )
{
n->setIsPlaying( true );
m_pattern->getInstrumentTrack()->processInEvent(
midiEvent( MidiNoteOn, 0, n->key(),
n->getVolume() * 127 / 100 ), midiTime() );
}
}
void pianoRoll::computeSelectedNotes(bool shift)
{
if( m_selectStartTick == 0 &&
@@ -1512,17 +1506,21 @@ void pianoRoll::mouseReleaseEvent( QMouseEvent * _me )
if( validPattern() == true )
{
if( m_action == ActionChangeNoteVolume && m_currentNote != NULL )
// turn off all notes that are playing
const noteVector & notes = m_pattern->notes();
noteVector::const_iterator it = notes.begin();
while( it != notes.end() )
{
m_pattern->getInstrumentTrack()->processInEvent(
midiEvent( MidiNoteOff, 0,
m_currentNote->key(), 0 ), midiTime() );
}
else
{
m_pattern->getInstrumentTrack()->processInEvent(
midiEvent( MidiNoteOff, 0, m_lastKey, 0 ),
midiTime() );
if( ( *it )->isPlaying() )
{
m_pattern->getInstrumentTrack()->processInEvent(
midiEvent( MidiNoteOff, 0, ( *it )->key(), 0 ),
midiTime() );
( *it )->setIsPlaying( false );
}
++it;
}
}
@@ -1566,8 +1564,7 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me )
// (could be the user just moved the cursor one pixel up/down
// but is still on the same key)
if( key_num != m_lastKey &&
m_action != ActionChangeNoteVolume &&
m_action != ActionMoveSelection &&
( m_action == ActionMoveNote || m_action == ActionMoveSelection ) &&
edit_note == false &&
_me->buttons() & Qt::LeftButton )
{
@@ -1606,96 +1603,66 @@ void pianoRoll::mouseMoveEvent( QMouseEvent * _me )
{
// Volume Bars
// Use nearest-note when changing volume so the bars can
// be "scribbled"
int pos_ticks = ( x * midiTime::ticksPerTact() ) /
m_ppt + m_currentPosition;
// Change notes within a certain pixel range of where
// the mouse cursor is
int pixel_range = 20;
// convert to ticks so that we can check which notes
// are in the range
int ticks_start = (x-pixel_range/2) *
midiTime::ticksPerTact() / m_ppt + m_currentPosition;
int ticks_end = (x+pixel_range/2) *
midiTime::ticksPerTact() / m_ppt + m_currentPosition;
// get note-vector of current pattern
const noteVector & notes = m_pattern->notes();
note * shortNote = NULL;
// Max "snap length" 1/8 note on either side
int shortDistance = DefaultTicksPerTact/8;
// loop through vector to find nearest note
noteVector::const_iterator it = notes.begin();
while( it != notes.end() )
{
int tmp = abs( pos_ticks - (int)( (*it)->pos() ) );
if( tmp <= shortDistance && (*it)->length().getTicks() > 0 )
{
shortDistance = tmp;
shortNote = *it ;
}
++it;
}
// determine what volume to set note to
volume vol = tLimit<int>( 2 * ( -_me->y() +
height() -
PR_BOTTOM_MARGIN ),
MinVolume,
MaxVolume );
if( shortNote )
// loop through vector
bool use_selection = isSelection();
noteVector::const_iterator it = notes.begin();
while( it != notes.end() )
{
// have short length - now check for volume difference and currentNote
it = notes.begin();
int shortNotePos = shortNote->pos();
int shortVolumeDiff = MaxVolume-MinVolume;
while( it != notes.end() )
if( ( *it )->pos().getTicks() >= ticks_start
&& ( *it )->pos().getTicks() <= ticks_end
&& ( *it )->length().getTicks() > 0
&& ( ( *it )->selected() || ! use_selection ) )
{
if( (*it)->pos() == shortNotePos && (*it)->length().getTicks() > 0 )
{
if( *it == m_currentNote )
{
shortNote = m_currentNote;
break;
}
int volDiff = abs( vol - (*it)->getVolume() );
if( volDiff <= shortVolumeDiff )
{
shortVolumeDiff = volDiff;
shortNote = *it;
}
}
++it;
}
}
if( shortNote != m_currentNote &&
engine::getSong()->isPlaying() == false )
{
if( m_currentNote != NULL ) {
( *it )->setVolume( vol );
m_pattern->dataChanged();
// play the note so that the user can tell how loud it is
testPlayNote( *it );
m_pattern->getInstrumentTrack()->processInEvent(
midiEvent( MidiNoteOff, 0,
m_currentNote->key(), 0 ), midiTime() );
midiEvent(
MidiKeyPressure,
0,
( *it )->key(),
vol * 127 / 100 ),
midiTime() );
}
else
{
if( ( *it )->isPlaying() )
{
// mouse not over this note, stop playing it.
m_pattern->getInstrumentTrack()->processInEvent(
midiEvent( MidiNoteOff, 0,
( *it )->key(), 0 ), midiTime() );
( *it )->setIsPlaying( false );
}
}
if( shortNote != NULL ) {
m_lastKey = shortNote->key();
++it;
m_pattern->getInstrumentTrack()->processInEvent(
midiEvent( MidiNoteOn, 0,
shortNote->key(), shortNote->getVolume() ), midiTime() );
}
}
m_currentNote = shortNote;
if( m_currentNote != NULL ) {
m_currentNote->setVolume( vol );
m_pattern->dataChanged();
m_pattern->getInstrumentTrack()->processInEvent(
midiEvent( MidiKeyPressure, 0, m_lastKey,
vol * 127 / 100 ),
midiTime() );
}
}
else if( _me->buttons() == Qt::NoButton && m_editMode == ModeDraw )