From 3948032d0a2e439069d9a6859f7f35eebb54944d Mon Sep 17 00:00:00 2001
From: Florian Jung <flo@windfisch.org>
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

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<Event*> 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<Event*>::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 <QDragLeaveEvent>
 #include <QTimer>
 
+#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 <set>
+
+#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<Event*> 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<Event*>::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 <QObject>
+#include <QTimer>
+
+#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