Just Intonation  Version 1.3.0 (18)
Explore scale-independent dynamically adapting tuning in just intonation
midihandler.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2016-2017 Karolin Stange, Christoph Wick, and Haye Hinrichsen
3  *
4  * This file is part of JustIntonation.
5  *
6  * JustIntonation is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * JustIntonation is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with JustIntonation. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 //=============================================================================
21 // Midi handler
22 //=============================================================================
23 
24 #include "midihandler.h"
25 
26 #include <QDebug>
27 
28 MidiHandler::MidiHandler(SoundGenerator &soundgenerator, AudioOutput &audiooutput)
29  : ThreadBase()
30  , pSoundGenerator(&soundgenerator)
31  , pAudioOutput(&audiooutput)
32  , mDrumChannels()
33  , mModulationWheel(-1)
34  , mPitchBendWheel(-1)
35  , mTemperamentIndex(1)
36 {
37  setThreadName("MidiHandler");
38  //mDrumChannels = {0x09};
39 }
40 
41 
42 #define STATUS if (mVerbosity >= 4) qDebug() << "MidiHandler:"
43 #define MESSAGE if (mVerbosity >= 3) qDebug() << "MidiHandler:"
44 #define WARNING if (mVerbosity >= 2) qWarning()<<"MidiHandler: WARNING:"
45 #define ERROR if (mVerbosity >= 1) qCritical() << "MidiHandler: ERROR:"
46 
47 
48 
49 
50 //-----------------------------------------------------------------------------
51 // Receive and interpret a MIDI event
52 //-----------------------------------------------------------------------------
53 
54 // https://www.midi.org/specifications/item/table-1-summary-of-midi-message
55 
56 void MidiHandler::receiveMidiEvent (const QMidiMessage &event)
57 {
58  if (not isActive()) return;
59  LOGSTATUS << "Received midi: " << event;
60 
61  Request request;
62  request.channel = event.byte0() & 0x0F;
63  request.key = event.byte1();
64  request.intensity = static_cast<double>(event.byte2())/127.0;
65  request.data = 0;
66 
67  auto send = [&request,this] (Request::Command c)
68  {
69  request.command=c;
71  };
72 
73  switch (event.byte0() & 0xF0)
74  {
75  case 0x80: // Note off
76  send(Request::NOTE_OFF);
77  break;
78 
79  case 0x90: // Note on
80  // TODO hit the drum
81  if (mDrumChannels.contains(event.byte0()&0x0F)) {}
82  else if (event.byte2() == 0) send(Request::NOTE_OFF);
83  else send(Request::NOTE_ON);
84  break;
85 
86  case 0xA0: // Polyphonic key pressure (aftertouch)
87  break;
88 
89  case 0xB0: // Control change
90  switch (event.byte1())
91  {
92  case 1: // Modulation wheel
93  {
94  if (event.byte2() != mModulationWheel)
95  {
96  int tempindex = mTemperamentIndex;
97  if (event.byte2() > 0x60 and tempindex != 1) tempindex = 1;
98  if (event.byte2() < 0x20 and tempindex != 0) tempindex = 0;
99  if (mTemperamentIndex!=tempindex)
100  {
101  setQmlTemperamentIndex(tempindex);
102  mTemperamentIndex = tempindex;
103  qDebug() << "Modulation wheel switches to temperament " << tempindex;
104  }
105  }
106  mModulationWheel = event.byte2();
107  break;
108  }
109  case 7: // volume change
110  {
111  double volume = 0.3 + 0.7 * event.byte2() / 127.0;
112  pAudioOutput->setVolume(volume);
113  break;
114  }
115  case 64: // Sustain pedal (right)
116  emit signalSustainPedal(event.byte2() != 0);
117  break;
118  case 66: // Sostenuto pedal (middle)
119  emit signalSostenutoPedal(event.byte2() != 0);
120  break;
121  case 67: // Soft pedal (left)
122  emit signalSoftPedal(event.byte2() != 0);
123  break;
124  case 123: // All notes off
126  }
127 
128  break;
129 
130  case 0xC0: // Program change
131  if (event.byte1() > 113) // if a drum is set
132  {
133  mDrumChannels.push_back(event.byte0()&0x0F);
134  LOGSTATUS << "Added drum on channel" << (event.byte0()&0x0F);
135  }
136  break;
137 
138  case 0xD0: // Channel pressure aftertouch
139  break;
140 
141  case 0xE0: // Pitch bend change
142  if (mPitchBendWheel != event.byte2())
143  {
144  if ((event.byte2() > mPitchBendWheel and event.byte2() > 0x40) or
145  (event.byte2() < mPitchBendWheel and event.byte2() < 0x40))
146  emit changeTargetFrequency(1.0/64*(event.byte2()-mPitchBendWheel));
147  }
148  mPitchBendWheel = event.byte2();
149  break;
150 
151 
152  case 0xF0: // System common messages
153  break;
154  }
155 }
156 
double intensity
Volume.
Definition: request.h:51
bool isActive() const
Return true if thread is running and not suspended.
Definition: threadbase.cpp:136
Universal base class for threaded modules.
Definition: threadbase.h:60
Class managing the generation of sound.
int mPitchBendWheel
Definition: midihandler.h:59
void signalSostenutoPedal(bool pressed)
Structure containing the data for a play-note request.
Definition: request.h:36
int mTemperamentIndex
Definition: midihandler.h:60
void changeTargetFrequency(QVariant df)
void registerRequest(Request &request)
Register a single request to play a note in the queue.
Command
Definition: request.h:38
void setVolume(double volume)
Set the global volume of the audio device.
void signalSoftPedal(bool pressed)
int channel
MIDI channel (0..15)
Definition: request.h:49
int mModulationWheel
Definition: midihandler.h:58
int key
Key index according to MIDI norm (0..127)
Definition: request.h:50
void receiveMidiEvent(const QMidiMessage &event)
Definition: midihandler.cpp:56
MidiHandler(SoundGenerator &soundgenerator, AudioOutput &audiooutput)
Definition: midihandler.cpp:28
Class for audio output.
Definition: audiooutput.h:45
Command command
command
Definition: request.h:48
void setQmlTemperamentIndex(QVariant index)
void registerAllNotesOff()
#define LOGSTATUS
Definition: log.h:42
AudioOutput * pAudioOutput
Definition: midihandler.h:56
SoundGenerator * pSoundGenerator
Definition: midihandler.h:55
QVector< quint8 > mDrumChannels
Definition: midihandler.h:57
void setThreadName(const QString name)
Set thread name (Linux only)
Definition: threadbase.cpp:121
Play a note with parameters listed below.
Definition: request.h:40
void signalSustainPedal(bool pressed)
int data
multipurpose data (do we really need that)
Definition: request.h:52
Stop playing the note.
Definition: request.h:41