diff --git a/include/midi.h b/include/midi.h index 1853f8c24..adc88dfb2 100644 --- a/include/midi.h +++ b/include/midi.h @@ -26,8 +26,8 @@ #ifndef _MIDI_H #define _MIDI_H - #include "lmms_basics.h" +#include "panning_constants.h" #include @@ -63,6 +63,7 @@ enum MidiEventTypes enum MidiMetaEvents { + MidiMetaInvalid = 0x00, MidiCopyright = 0x02, MidiTrackName = 0x03, MidiInstName = 0x04, @@ -75,7 +76,9 @@ enum MidiMetaEvents MidiSMPTEOffset = 0x54, MidiTimeSignature = 0x58, MidiKeySignature = 0x59, - MidiSequencerEvent = 0x7f + MidiSequencerEvent = 0x7f, + MidiMetaCustom = 0x80, + MidiNotePanning } ; @@ -84,6 +87,9 @@ const int MidiControllerCount = 128; const int MidiProgramCount = 128; const int MidiMaxVelocity = 127; +const int MidiMaxPanning = 127; +const int MidiMinPanning = -128; + struct midiEvent { @@ -92,6 +98,7 @@ struct midiEvent Sint16 _param1 = 0, Sint16 _param2 = 0 ) : m_type( _type ), + m_metaEvent( MidiMetaInvalid ), m_channel( _channel ), m_sysExData( NULL ) { @@ -101,6 +108,7 @@ struct midiEvent midiEvent( MidiEventTypes _type, const char * _sysex_data, int _data_len ) : m_type( _type ), + m_metaEvent( MidiMetaInvalid ), m_channel( 0 ), m_sysExData( _sysex_data ) { @@ -109,6 +117,7 @@ struct midiEvent midiEvent( const midiEvent & _copy ) : m_type( _copy.m_type ), + m_metaEvent( _copy.m_metaEvent ), m_channel( _copy.m_channel ), m_data( _copy.m_data ), m_sysExData( _copy.m_sysExData ) @@ -139,14 +148,28 @@ struct midiEvent { return m_data.m_param[1]; } + + inline Sint16 midiPanning( void ) const + { + return m_data.m_param[1]; + } inline volume getVolume( void ) const { return (volume)( velocity() * 100 / MidiMaxVelocity ); } + + inline panning getPanning( void ) const + { + return (panning) ( PanningLeft + + ( (float)( midiPanning() - MidiMinPanning ) ) / + ( (float)( MidiMaxPanning - MidiMinPanning ) ) * + ( (float)( PanningRight - PanningLeft ) ) ); + } MidiEventTypes m_type; // MIDI event type + MidiMetaEvents m_metaEvent; // Meta event (mostly unused) Sint8 m_channel; // MIDI channel union { diff --git a/include/note.h b/include/note.h index 5cbd287db..9927bcc11 100644 --- a/include/note.h +++ b/include/note.h @@ -90,7 +90,21 @@ public: detuningHelper * _detuning = NULL ); 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; } + inline void setOldLength( const midiTime & _oldLength ) + { + m_oldLength = _oldLength; + } + inline void setIsPlaying( const bool _isPlaying ) + { + m_isPlaying = _isPlaying; + } + + void setLength( const midiTime & _length ); void setPos( const midiTime & _pos ); void setKey( const int _key ); @@ -99,6 +113,38 @@ public: void quantizeLength( const int _q_grid ); void quantizePos( const int _q_grid ); + static inline bool lessThan(note * &lhs, note * &rhs) + { + // function to compare two notes - must be called explictly when + // using qSort + return (bool) ((int) ( *lhs ).pos() < (int) ( *rhs ).pos()); + } + + inline bool selected( void ) const + { + return m_selected; + } + + inline int oldKey( void ) const + { + return m_oldKey; + } + + inline midiTime oldPos( void ) const + { + return m_oldPos; + } + + inline midiTime oldLength( void ) const + { + return m_oldLength; + } + + inline bool isPlaying( void ) const + { + return m_isPlaying; + } + inline midiTime endPos( void ) const { const int l = length(); @@ -177,7 +223,14 @@ 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; panning m_panning; diff --git a/include/panning.h b/include/panning.h index 0ff61c38e..ea656f562 100644 --- a/include/panning.h +++ b/include/panning.h @@ -1,5 +1,5 @@ /* - * panning.h - declaration of some constants and types, concerning the + * panning.h - declaration of some types, concerning the * panning of a note * * Copyright (c) 2004-2008 Tobias Doerffel @@ -29,11 +29,8 @@ #include "lmms_basics.h" #include "volume.h" #include "templates.h" - -const panning PanningRight = ( 0 + 100 ); -const panning PanningLeft = - PanningRight; -const panning PanningCenter = 0; -const panning DefaultPanning = PanningCenter; +#include "panning_constants.h" +#include "midi.h" inline stereoVolumeVector panningToVolumeVector( panning _p, float _scale = 1.0f ) @@ -44,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/panning_constants.h b/include/panning_constants.h new file mode 100644 index 000000000..90fc01673 --- /dev/null +++ b/include/panning_constants.h @@ -0,0 +1,34 @@ +/* + * panning_constants.h - declaration of some constants, concerning the + * panning of a note + * + * Copyright (c) 2004-2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef _PANNING_CONSTANTS_H +#define _PANNING_CONSTANTS_H + +const panning PanningRight = ( 0 + 100 ); +const panning PanningLeft = - PanningRight; +const panning PanningCenter = 0; +const panning DefaultPanning = PanningCenter; + +#endif diff --git a/include/pattern.h b/include/pattern.h index 4acd1c6d7..cb75581ae 100644 --- a/include/pattern.h +++ b/include/pattern.h @@ -68,13 +68,14 @@ public: virtual midiTime length( void ) const; midiTime beatPatternLength( void ) const; + // note management note * addNote( const note & _new_note, const bool _quant_pos = true ); void removeNote( const note * _note_to_del ); note * rearrangeNote( const note * _note_to_proc, const bool _quant_pos = true ); - + void rearrangeAllNotes( void ); void clearNotes( void ); inline const noteVector & notes( void ) @@ -132,6 +133,10 @@ public: using model::dataChanged; + + + void printNotes( void ); // for debugging purposes + protected: diff --git a/include/piano_roll.h b/include/piano_roll.h index 5742fa49f..a4fd75bc0 100644 --- a/include/piano_roll.h +++ b/include/piano_roll.h @@ -3,6 +3,7 @@ * can set and edit notes in an easy way * * Copyright (c) 2004-2008 Tobias Doerffel + * Copyright (c) 2008 Andrew Kelley * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -38,6 +39,9 @@ class QPainter; class QPixmap; class QScrollBar; +class QString; +class QMenu; +class QSignalMapper; class comboBox; class notePlayHandle; @@ -54,17 +58,17 @@ public: inline bool isRecording( void ) const { - return( m_recording ); + return m_recording; } inline const pattern * currentPattern( void ) const { - return( m_pattern ); + return m_pattern; } inline bool validPattern( void ) const { - return( m_pattern != NULL ); + return m_pattern != NULL; } int quantization( void ) const; @@ -75,7 +79,7 @@ public: inline virtual QString nodeName( void ) const { - return( "pianoroll" ); + return "pianoroll"; } @@ -85,20 +89,16 @@ protected: virtual void keyReleaseEvent( QKeyEvent * _ke ); virtual void leaveEvent( QEvent * _e ); virtual void mousePressEvent( QMouseEvent * _me ); + virtual void mouseDoubleClickEvent( QMouseEvent * _me ); virtual void mouseReleaseEvent( QMouseEvent * _me ); virtual void mouseMoveEvent( QMouseEvent * _me ); virtual void paintEvent( QPaintEvent * _pe ); virtual void resizeEvent( QResizeEvent * _re ); virtual void wheelEvent( QWheelEvent * _we ); -#ifdef LMMS_BUILD_LINUX - virtual bool x11Event( XEvent * _xe ); -#endif int getKey( int _y ) const; static inline void drawNoteRect( QPainter & _p, int _x, int _y, - int _width, - const bool _is_selected, - const bool _is_step_note ); + int _width, note * _n ); void removeSelection( void ); void selectAll( void ); void getSelectedNotes( noteVector & _selected_notes ); @@ -118,7 +118,7 @@ protected slots: void drawButtonToggled( void ); void eraseButtonToggled( void ); void selectButtonToggled( void ); - void moveButtonToggled( void ); + void detuneButtonToggled( void ); void copySelectedNotes( void ); void cutSelectedNotes( void ); @@ -129,6 +129,8 @@ protected slots: void zoomingChanged( void ); void quantizeChanged( void ); + + void changeNoteEditMode( int i ); private: @@ -138,9 +140,8 @@ private: ModeDraw, ModeErase, ModeSelect, - ModeMove, ModeOpen - } ; + }; enum actions { @@ -148,26 +149,54 @@ private: ActionMoveNote, ActionResizeNote, ActionSelectNotes, - ActionMoveSelection, - ActionChangeNoteVolume, - ActionChangeNotePanning - } ; + ActionChangeNoteProperty, + ActionResizeNoteEditArea + }; + + enum noteEditMode + { + NoteEditVolume, + NoteEditPanning, + NoteEditCount // make sure this one is always last + }; enum pianoRollKeyTypes { PR_WHITE_KEY_SMALL, PR_WHITE_KEY_BIG, PR_BLACK_KEY - } ; + }; + QVector m_nemStr; // gui names of each edit mode + QMenu * m_noteEditMenu; // when you right click below the key area + QSignalMapper * m_signalMapper; // to keep track of edit mode events pianoRoll( void ); pianoRoll( const pianoRoll & ); virtual ~pianoRoll(); midiTime newNoteLen( void ) const; - - + + void shiftPos(int amount); + void shiftSemiTone(int amount); + bool isSelection() const; + int selectionCount() 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; + inline int noteEditBottom() const; + inline int keyAreaTop() const; + inline int noteEditRight() const; + inline int noteEditLeft() const; + + void dragNotes( int x, int y, bool alt ); + + static const int cm_scrollAmtHoriz = 10; + static const int cm_scrollAmtVert = 1; + static QPixmap * s_whiteKeyBigPm; static QPixmap * s_whiteKeySmallPm; static QPixmap * s_blackKeyPm; @@ -190,8 +219,8 @@ private: toolButton * m_drawButton; toolButton * m_eraseButton; toolButton * m_selectButton; - toolButton * m_moveButton; - + toolButton * m_detuneButton; + toolButton * m_cutButton; toolButton * m_copyButton; toolButton * m_pasteButton; @@ -215,30 +244,51 @@ private: note * m_currentNote; actions m_action; + noteEditMode m_noteEditMode; Uint32 m_selectStartTick; int m_selectedTick; int m_selectStartKey; int m_selectedKeys; + + // boundary box around all selected notes when dragging + int m_moveBoundaryLeft; + int m_moveBoundaryTop; + int m_moveBoundaryRight; + int m_moveBoundaryBottom; + + // remember where the scrolling started when dragging so that + // we can handle dragging while scrolling with arrow keys + int m_mouseDownKey; + int m_mouseDownTick; + + // remember the last x and y of a mouse movement + int m_lastMouseX; + int m_lastMouseY; + + // x,y of when the user starts a drag + int m_moveStartX; + int m_moveStartY; - int m_moveStartKey; - int m_moveStartTick; - int m_moveXOffset; - + int m_oldNotesEditHeight; int m_notesEditHeight; int m_ppt; int m_totalKeysToScroll; + // remember these values to use them + // for the next note that is set midiTime m_lenOfNewNotes; + volume m_lastNoteVolume; + panning m_lastNotePanning; int m_startKey; // first key when drawing int m_lastKey; - noteVector m_selNotesForMove; - - editModes m_editMode; - + editModes m_ctrlMode; // mode they were in before they hit ctrl + + bool m_mouseDownLeft; //true if left click is being held down + bool m_mouseDownRight; //true if right click is being held down timeLine * m_timeLine; bool m_scrollBack; @@ -249,8 +299,10 @@ private: bool mouseOverNote( void ); note * noteUnderMouse( void ); noteVector::const_iterator noteIteratorUnderMouse( void ); - - + + // turn a selection rectangle into selected notes + void computeSelectedNotes( bool shift ); + void clearSelectedNotes( void ); friend class engine; diff --git a/src/core/note.cpp b/src/core/note.cpp index c527ec99a..f37c32403 100644 --- a/src/core/note.cpp +++ b/src/core/note.cpp @@ -40,6 +40,11 @@ note::note( const midiTime & _length, const midiTime & _pos, int _key, volume _volume, panning _panning, detuningHelper * _detuning ) : + m_selected( false ), + 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 ) ), @@ -48,7 +53,6 @@ note::note( const midiTime & _length, const midiTime & _pos, { //saveJournallingState( FALSE ); // setJournalling( FALSE ); - if( _detuning ) { m_detuning = sharedObject::ref( _detuning ); @@ -65,6 +69,11 @@ note::note( const midiTime & _length, const midiTime & _pos, note::note( const note & _note ) : serializingObject( _note ), + m_selected( _note.m_selected ), + 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 ), diff --git a/src/core/piano.cpp b/src/core/piano.cpp index cb8a740a5..503d99627 100644 --- a/src/core/piano.cpp +++ b/src/core/piano.cpp @@ -506,7 +506,7 @@ void pianoView::mousePressEvent( QMouseEvent * _me ) } else { - if( engine::getMainWindow()->isCtrlPressed() ) + if( _me->modifiers() & Qt::ControlModifier ) { new stringPairDrag( "automatable_model", QString::number( m_piano-> diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp index 2a98c4642..ddc54e109 100644 --- a/src/tracks/pattern.cpp +++ b/src/tracks/pattern.cpp @@ -34,6 +34,8 @@ #include #include #include +#include + #include "pattern.h" @@ -96,8 +98,6 @@ pattern::pattern( const pattern & _pat_to_copy ) : } - - pattern::~pattern() { for( noteVector::iterator it = m_notes.begin(); @@ -183,6 +183,17 @@ midiTime pattern::beatPatternLength( void ) const +void pattern::printNotes( void ) +{ + for( noteVector::iterator it = m_notes.begin(); it != m_notes.end(); + ++it ) + { + printf("note (pos = %i)\n", (int) ( *it )->pos() ); + } + printf("\n"); +} + + note * pattern::addNote( const note & _new_note, const bool _quant_pos ) { @@ -270,6 +281,13 @@ note * pattern::rearrangeNote( const note * _note_to_proc, +void pattern::rearrangeAllNotes( void ) +{ + // sort notes by start time + qSort(m_notes.begin(), m_notes.end(), note::lessThan ); +} + + void pattern::clearNotes( void ) { @@ -1034,7 +1052,7 @@ void patternView::mousePressEvent( QMouseEvent * _me ) } else if( m_pat->m_frozenPattern != NULL && _me->button() == Qt::LeftButton && - engine::getMainWindow()->isShiftPressed() == true ) + _me->modifiers() & Qt::ShiftModifier ) { QString s; new stringPairDrag( "sampledata",