From 3948032d0a2e439069d9a6859f7f35eebb54944d Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 25 May 2011 17:27:35 +0000 Subject: added step recording for drum edit step-recording stuff has been put into a easy-to-use StepRec class the midi-in and step-rec buttons are now fully functional again --- muse2/muse/CMakeLists.txt | 2 + muse2/muse/midiedit/dcanvas.cpp | 24 ++++++ muse2/muse/midiedit/dcanvas.h | 8 +- muse2/muse/midiedit/drumedit.cpp | 7 -- muse2/muse/midiedit/prcanvas.cpp | 161 ++------------------------------------- muse2/muse/midiedit/prcanvas.h | 7 +- muse2/muse/steprec.cpp | 159 ++++++++++++++++++++++++++++++++++++++ muse2/muse/steprec.h | 36 +++++++++ 8 files changed, 237 insertions(+), 167 deletions(-) create mode 100644 muse2/muse/steprec.cpp create mode 100644 muse2/muse/steprec.h (limited to 'muse2') diff --git a/muse2/muse/CMakeLists.txt b/muse2/muse/CMakeLists.txt index e6a90a59..cea95083 100644 --- a/muse2/muse/CMakeLists.txt +++ b/muse2/muse/CMakeLists.txt @@ -63,6 +63,7 @@ QT4_WRAP_CPP ( muse_moc_headers song.h transport.h value.h + steprec.h ) ## @@ -135,6 +136,7 @@ file (GLOB core_source_files waveevent.cpp wavetrack.cpp xml.cpp + steprec.cpp ) file (GLOB main_source_files main.cpp diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index eea29b46..4f904be1 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -88,7 +88,11 @@ DrumCanvas::DrumCanvas(MidiEditor* pr, QWidget* parent, int sx, setVirt(false); cursorPos= QPoint(0,0); _stepSize=1; + + steprec=new StepRec(NULL); + songChanged(SC_TRACK_INSERTED); + connect(song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int))); } //--------------------------------------------------------- @@ -1063,6 +1067,10 @@ void DrumCanvas::keyPressed(int index, int velocity) // play note: MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); audio->msgPlayMidiEvent(&e); + + if (_steprec && pos[0] >= start_tick && pos[0] < end_tick && curPart) + steprec->record(curPart,index,drumMap[index].len,editor->raster(),velocity,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); + } //--------------------------------------------------------- @@ -1503,3 +1511,19 @@ void DrumCanvas::moveAwayUnused() used.erase(it++); } } + + +//--------------------------------------------------------- +// midiNote +//--------------------------------------------------------- +void DrumCanvas::midiNote(int pitch, int velo) + { + if (debugMsg) printf("DrumCanvas::midiNote: pitch=%i, velo=%i\n", pitch, velo); + + if (_midiin && _steprec && curPart + && !audio->isPlaying() && velo && pos[0] >= start_tick + && pos[0] < end_tick + && !(globalKeyState & Qt::AltModifier)) { + steprec->record(curPart,drumInmap[pitch],drumMap[(int)drumInmap[pitch]].len,editor->raster(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); + } + } diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h index b86bc2d7..5a1fefeb 100644 --- a/muse2/muse/midiedit/dcanvas.h +++ b/muse2/muse/midiedit/dcanvas.h @@ -10,6 +10,7 @@ #include "ecanvas.h" #include "song.h" +#include "steprec.h" #define TH 18 @@ -40,7 +41,9 @@ class PianoRoll; //--------------------------------------------------------- class DrumCanvas : public EventCanvas { - + + StepRec* steprec; + // Cursor tool position QPoint cursorPos; int _stepSize; @@ -77,6 +80,9 @@ class DrumCanvas : public EventCanvas { signals: void newWidth(int); + private slots: + void midiNote(int pitch, int velo); + public slots: void mapChanged(int, int); void keyPressed(int, int); diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index 4d632984..4d2fae93 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -295,21 +295,14 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini srec->setToolTip(tr("Step Record")); srec->setIcon(*steprecIcon); srec->setCheckable(true); - srec->setEnabled(false); //disabled by flo93 (see below) tools->addWidget(srec); midiin = new QToolButton(); midiin->setToolTip(tr("Midi Input")); midiin->setIcon(*midiinIcon); midiin->setCheckable(true); - midiin->setEnabled(false); //disabled by flo93 (see below) tools->addWidget(midiin); - // I disabled these buttons because they're without function; - // muse should not lie to the user pretending some functionality - // it doesn't have; they should be enabled as soon step-recording - // has been implemented. - tools2 = new EditToolBar(this, drumeditTools); addToolBar(tools2); diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index 7794c520..75ad3c06 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -37,8 +37,6 @@ #include "song.h" #include "audio.h" -#define CHORD_TIMEOUT 75 - //--------------------------------------------------------- // NEvent //--------------------------------------------------------- @@ -87,13 +85,8 @@ PianoCanvas::PianoCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy) playedPitch = -1; for (int i=0;i<128;i++) noteHeldDown[i]=false; - chordTimer = new QTimer(this); - chordTimer->setSingleShot(true); - chordTimer->setInterval(CHORD_TIMEOUT); - chordTimer->stop(); + steprec=new StepRec(noteHeldDown); - connect(chordTimer, SIGNAL(timeout()), SLOT(chordTimerTimedOut())); - songChanged(SC_TRACK_INSERTED); connect(song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int))); } @@ -778,27 +771,9 @@ void PianoCanvas::pianoPressed(int pitch, int velocity, bool shift) //MidiPlayEvent e(0, port, channel, 0x90, pitch, 127); MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); audio->msgPlayMidiEvent(&e); - - if (_steprec && pos[0] >= start_tick && pos[0] < end_tick) { - if (curPart) { - int len = editor->raster(); - unsigned tick = pos[0] - curPart->tick(); //CDW - if (shift) - tick -= editor->rasterStep(tick); - Event e(Note); - e.setTick(tick); - e.setPitch(pitch); - e.setVelo(127); - e.setLenTick(len); - // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgAddEvent(e, curPart); - audio->msgAddEvent(e, curPart, true, false, false); - tick += editor->rasterStep(tick) + curPart->tick(); - if (tick != song->cpos()) { - Pos p(tick, true); - song->setPos(0, p, true, false, true); - } - } + + if (_steprec && pos[0] >= start_tick && pos[0] < end_tick && curPart) { + steprec->record(curPart,pitch,editor->raster(),editor->raster(),velocity,globalKeyState&Qt::ControlModifier,shift); } } @@ -1077,136 +1052,10 @@ void PianoCanvas::midiNote(int pitch, int velo) && !audio->isPlaying() && velo && pos[0] >= start_tick && pos[0] < end_tick && !(globalKeyState & Qt::AltModifier)) { - - if (pitch!=rcSteprecNote) { - chordTimer->stop(); - - //len has been changed by flo: set to raster() instead of quant() - //reason: the quant-toolbar has been removed; the flexibility you - //lose with this can be re-gained by applying a "modify note len" - //on the notes you have entered. - unsigned int len = editor->raster();//prevent compiler warning: comparison singed/unsigned - unsigned tick = pos[0]; //CDW - unsigned starttick = tick; - - // - // extend len of last note? - // - EventList* events = curPart->events(); - if (globalKeyState & Qt::ControlModifier) { - for (iEvent i = events->begin(); i != events->end(); ++i) { - Event ev = i->second; - if (!ev.isNote()) - continue; - if (ev.pitch() == pitch && ((ev.tick() + ev.lenTick()) == /*(int)*/starttick)) { - Event e = ev.clone(); - e.setLenTick(ev.lenTick() + editor->rasterStep(starttick)); - // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgChangeEvent(ev, e, curPart); - audio->msgChangeEvent(ev, e, curPart, true, false, false); - - if (! (globalKeyState & Qt::ShiftModifier)) { - chordTimer_setToTick = tick + editor->rasterStep(tick); - chordTimer->start(); - } - return; - } - } - } - - // - // if we already entered the note, delete it - // - EventRange range = events->equal_range(tick); - for (iEvent i = range.first; i != range.second; ++i) { - Event ev = i->second; - if (ev.isNote() && ev.pitch() == pitch) { - // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgDeleteEvent(ev, curPart); - audio->msgDeleteEvent(ev, curPart, true, false, false); - - if (! (globalKeyState & Qt::ShiftModifier)) { - chordTimer_setToTick = tick + editor->rasterStep(tick); - chordTimer->start(); - } - - return; - } - } - Event e(Note); - e.setTick(tick - curPart->tick()); - e.setPitch(pitch); - e.setVelo(velo); - e.setLenTick(len); - // Indicate do undo, and do not do port controller values and clone parts. - //audio->msgAddEvent(e, curPart); - audio->msgAddEvent(e, curPart, true, false, false); - - if (! (globalKeyState & Qt::ShiftModifier)) { - chordTimer_setToTick = tick + editor->rasterStep(tick); - chordTimer->start(); - } - } - else { // equals if (pitch==rcSteprecNote) - bool held_notes=false; - for (int i=0;i<128;i++) - if (noteHeldDown[i]) { held_notes=true; break; } - - if (held_notes) - { - chordTimer->stop(); - - unsigned tick = pos[0]; - - // extend len of last note(s) - using std::set; - - set extend_set; - EventList* events = curPart->events(); - for (iEvent i = events->begin(); i != events->end(); ++i) { - Event& ev = i->second; - if (!ev.isNote()) - continue; - - if (noteHeldDown[ev.pitch()] && ((ev.tick() + ev.lenTick()) == tick)) - extend_set.insert(&ev); - } - for (set::iterator it=extend_set.begin(); it!=extend_set.end(); it++) - { - Event& ev=**it; - Event e = ev.clone(); - e.setLenTick(ev.lenTick() + editor->rasterStep(tick)); - // Indicate do undo, and do not do port controller values and clone parts. - audio->msgChangeEvent(ev, e, curPart, true, false, false); - } - - if (! (globalKeyState & Qt::ShiftModifier)) { - chordTimer_setToTick = tick + editor->rasterStep(tick); - chordTimer->start(); - } - return; - - } - else // equals if (!held_notes) - { - chordTimer->stop(); - - //simply proceed, inserting a rest - Pos p(pos[0] + editor->rasterStep(pos[0]), true); - song->setPos(0, p, true, false, true); - } - } + steprec->record(curPart,pitch,editor->raster(),editor->raster(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier); } } -void PianoCanvas::chordTimerTimedOut() -{ - if (chordTimer_setToTick != song->cpos()) - { - Pos p(chordTimer_setToTick, true); - song->setPos(0, p, true, false, true); - } -} /* //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index c6d84e88..b9da00c6 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -17,6 +17,8 @@ #include #include +#include "steprec.h" + #define KH 13 //--------------------------------------------------------- @@ -41,9 +43,9 @@ class PianoCanvas : public EventCanvas { int colorMode; int playedPitch; - QTimer* chordTimer; - unsigned chordTimer_setToTick; bool noteHeldDown[128]; + + StepRec* steprec; Q_OBJECT virtual void viewMouseDoubleClickEvent(QMouseEvent*); @@ -77,7 +79,6 @@ class PianoCanvas : public EventCanvas { private slots: void midiNote(int pitch, int velo); - void chordTimerTimedOut(); signals: void quantChanged(int); diff --git a/muse2/muse/steprec.cpp b/muse2/muse/steprec.cpp new file mode 100644 index 00000000..29cb9540 --- /dev/null +++ b/muse2/muse/steprec.cpp @@ -0,0 +1,159 @@ +//========================================================= +// MusE +// Linux Music Editor +// steprec.cpp +// (C) Copyright 2011 Florian Jung (flo93@users.sourceforge.net) +//========================================================= + +#include "steprec.h" +#include "part.h" +#include "event.h" +#include "globals.h" + +#include "song.h" +#include "audio.h" + +#include + +#define CHORD_TIMEOUT 75 + +StepRec::StepRec(bool* note_held_down_array) +{ + note_held_down=note_held_down_array; + + chord_timer=new QTimer(this); + chord_timer->setSingleShot(true); + chord_timer->setInterval(CHORD_TIMEOUT); + chord_timer->stop(); + connect(chord_timer, SIGNAL(timeout()), SLOT(timeout())); +} + +void StepRec::timeout() +{ + if (chord_timer_set_to_tick != song->cpos()) + { + Pos p(chord_timer_set_to_tick, true); + song->setPos(0, p, true, false, true); + } +} + +void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ctrl, bool shift) +{ + unsigned tick = song->cpos(); + + if (pitch!=rcSteprecNote) { + chord_timer->stop(); + + + // + // extend len of last note? + // + EventList* events = part->events(); + if (ctrl) { + for (iEvent i = events->begin(); i != events->end(); ++i) { + Event ev = i->second; + if (!ev.isNote()) + continue; + if (ev.pitch() == pitch && ((ev.tick() + ev.lenTick()) == tick)) { + Event e = ev.clone(); + e.setLenTick(ev.lenTick() + len); + // Indicate do undo, and do not do port controller values and clone parts. + audio->msgChangeEvent(ev, e, part, true, false, false); + + if (!shift) { + chord_timer_set_to_tick = tick + step; + chord_timer->start(); + } + return; + } + } + } + + // + // if we already entered the note, delete it + // + EventRange range = events->equal_range(tick); + for (iEvent i = range.first; i != range.second; ++i) { + Event ev = i->second; + if (ev.isNote() && ev.pitch() == pitch) { + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, part); + audio->msgDeleteEvent(ev, part, true, false, false); + + if (!shift) { + chord_timer_set_to_tick = tick + step; + chord_timer->start(); + } + + return; + } + } + + Event e(Note); + e.setTick(tick - part->tick()); + e.setPitch(pitch); + e.setVelo(velo); + e.setLenTick(len); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(e, part); + audio->msgAddEvent(e, part, true, false, false); + + if (! (globalKeyState & Qt::ShiftModifier)) { + chord_timer_set_to_tick = tick + step; + chord_timer->start(); + } + } + else { // equals if (pitch==rcSteprecNote) + bool held_notes=false; + if (note_held_down!=NULL) + { + for (int i=0;i<128;i++) + if (note_held_down[i]) { held_notes=true; break; } + } + else + held_notes=false; + + + if (held_notes) + { + chord_timer->stop(); + + // extend len of last note(s) + using std::set; + + set extend_set; + EventList* events = part->events(); + for (iEvent i = events->begin(); i != events->end(); ++i) { + Event& ev = i->second; + if (!ev.isNote()) + continue; + + if (note_held_down[ev.pitch()] && ((ev.tick() + ev.lenTick()) == tick)) + extend_set.insert(&ev); + } + for (set::iterator it=extend_set.begin(); it!=extend_set.end(); it++) + { + Event& ev=**it; + Event e = ev.clone(); + e.setLenTick(ev.lenTick() + len); + // Indicate do undo, and do not do port controller values and clone parts. + audio->msgChangeEvent(ev, e, part, true, false, false); + } + + if (!shift) { + chord_timer_set_to_tick = tick + step; + chord_timer->start(); + } + return; + + } + else // equals if (!held_notes) + { + chord_timer->stop(); + + //simply proceed, inserting a rest + Pos p(song->cpos() + step, true); + song->setPos(0, p, true, false, true); + } + } +} diff --git a/muse2/muse/steprec.h b/muse2/muse/steprec.h new file mode 100644 index 00000000..b09a9edd --- /dev/null +++ b/muse2/muse/steprec.h @@ -0,0 +1,36 @@ +//========================================================= +// MusE +// Linux Music Editor +// steprec.h +// (C) Copyright 2011 Florian Jung (flo93@users.sourceforge.net) +//========================================================= + +#ifndef __STEPREC_H__ +#define __STEPREC_H__ + +#include +#include + +#include "part.h" + + +class StepRec : public QObject +{ + Q_OBJECT + + public: + StepRec(bool* note_held_down_array); + + void record(Part* part, int pitch, int len, int step, int velo=80, bool ctrl=false, bool shift=false); + + private slots: + void timeout(); + + private: + QTimer* chord_timer; + int chord_timer_set_to_tick; + bool* note_held_down; + +}; + +#endif -- cgit v1.2.3