root/branches/text_encodings/libs/hydrogen/src/IO/midi_input.cpp @ 939

Revision 939, 9.0 KB (checked in by gabriel@…, 4 years ago)

Reduce explicit casts from char* to QString.

Typically these two patterns:

- QString foo = "";
+ QString foo;

QString bar

- if( bar == "" ) {
+ if( bar.isEmpty() ) {

Line 
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 *
5 * http://www.hydrogen-music.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY, without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 *
21 */
22
23#include <hydrogen/IO/MidiInput.h>
24#include <hydrogen/event_queue.h>
25#include <hydrogen/Preferences.h>
26#include <hydrogen/hydrogen.h>
27#include <hydrogen/instrument.h>
28#include <hydrogen/note.h>
29#include <hydrogen/action.h>
30#include <hydrogen/midiMap.h>
31
32namespace H2Core
33{
34
35MidiInput::MidiInput( const QString class_name )
36                : Object( class_name )
37                , m_bActive( false )
38{
39        //INFOLOG( "INIT" );
40       
41}
42
43
44MidiInput::~MidiInput()
45{
46        //INFOLOG( "DESTROY" );
47}
48
49void MidiInput::handleMidiMessage( const MidiMessage& msg )
50{
51        EventQueue::get_instance()->push_event( EVENT_MIDI_ACTIVITY, -1 );
52
53//      infoLog( "[handleMidiMessage]" );
54//      infoLog( "[handleMidiMessage] channel: " + to_string( msg.m_nChannel ) );
55//      infoLog( "[handleMidiMessage] val1: " + to_string( msg.m_nData1 ) );
56//      infoLog( "[handleMidiMessage] val2: " + to_string( msg.m_nData2 ) );
57
58        switch ( msg.m_type ) {
59        case MidiMessage::SYSEX:
60                handleSysexMessage( msg );
61                break;
62
63        case MidiMessage::NOTE_ON:
64                handleNoteOnMessage( msg );
65                break;
66
67        case MidiMessage::NOTE_OFF:
68                handleNoteOffMessage( msg );
69                break;
70
71        case MidiMessage::POLYPHONIC_KEY_PRESSURE:
72                ERRORLOG( "POLYPHONIC_KEY_PRESSURE event not handled yet" );
73                break;
74
75        case MidiMessage::CONTROL_CHANGE:
76                INFOLOG( QString( "[handleMidiMessage] CONTROL_CHANGE Parameter: %1, Value: %2").arg( msg.m_nData1 ).arg( msg.m_nData2 ) );
77                handleControlChangeMessage( msg );
78                break;
79
80        case MidiMessage::PROGRAM_CHANGE:
81                INFOLOG( QString( "[handleMidiMessage] PROGRAM_CHANGE event, seting next pattern to %1" ).arg( msg.m_nData1 ) );
82                Hydrogen::get_instance()->sequencer_setNextPattern(msg.m_nData1, false, false);
83                break;
84
85        case MidiMessage::CHANNEL_PRESSURE:
86                ERRORLOG( "CHANNEL_PRESSURE event not handled yet" );
87                break;
88
89        case MidiMessage::PITCH_WHEEL:
90                ERRORLOG( "PITCH_WHEEL event not handled yet" );
91                break;
92
93        case MidiMessage::SYSTEM_EXCLUSIVE:
94                ERRORLOG( "SYSTEM_EXCLUSIVE event not handled yet" );
95                break;
96
97        case MidiMessage::START:
98                INFOLOG( "START event" );
99                if ( Hydrogen::get_instance()->getState() != STATE_PLAYING ) {
100                        Hydrogen::get_instance()->sequencer_play();
101                }
102                break;
103
104        case MidiMessage::CONTINUE:
105                ERRORLOG( "CONTINUE event not handled yet" );
106                break;
107
108        case MidiMessage::STOP:
109                INFOLOG( "STOP event" );
110                if ( Hydrogen::get_instance()->getState() == STATE_PLAYING ) {
111                        Hydrogen::get_instance()->sequencer_stop();
112                }
113                break;
114
115        case MidiMessage::SONG_POS:
116                ERRORLOG( "SONG_POS event not handled yet" );
117                break;
118
119        case MidiMessage::QUARTER_FRAME:
120                WARNINGLOG( "QUARTER_FRAME event not handled yet" );
121                break;
122
123        case MidiMessage::UNKNOWN:
124                ERRORLOG( "Unknown midi message" );
125                break;
126
127        default:
128                ERRORLOG( QString( "unhandled midi message type: %1" ).arg( msg.m_type ) );
129        }
130}
131
132void MidiInput::handleControlChangeMessage( const MidiMessage& msg )
133{
134        //INFOLOG( QString( "[handleMidiMessage] CONTROL_CHANGE Parameter: %1, Value: %2" ).arg( msg.m_nData1 ).arg( msg.m_nData2 ) );
135       
136        Hydrogen *pEngine = Hydrogen::get_instance();
137        ActionManager * aH = ActionManager::getInstance();
138        MidiMap * mM = MidiMap::getInstance();
139
140        Action * pAction;
141
142        pAction = mM->getCCAction( msg.m_nData1 );
143        pAction->setParameter2( QString::number( msg.m_nData2 ) );
144
145        aH->handleAction( pAction );
146
147        pEngine->lastMidiEvent = "CC";
148        pEngine->lastMidiEventParameter = msg.m_nData1;
149       
150
151}
152
153void MidiInput::handleNoteOnMessage( const MidiMessage& msg )
154{
155        INFOLOG( "handleNoteOnMessage" );
156
157
158        int nMidiChannelFilter = Preferences::getInstance()->m_nMidiChannelFilter;
159        int nChannel = msg.m_nChannel;
160        int nNote = msg.m_nData1;
161        float fVelocity = msg.m_nData2 / 127.0;
162
163        if ( fVelocity == 0 ) {
164                handleNoteOffMessage( msg );
165                return;
166        }
167
168
169        bool bIsChannelValid = true;
170        if ( nMidiChannelFilter != -1 ) {
171                bIsChannelValid = ( nChannel == nMidiChannelFilter );
172        }
173
174        ActionManager * aH = ActionManager::getInstance();
175        MidiMap * mM = MidiMap::getInstance();
176        Hydrogen *pEngine = Hydrogen::get_instance();
177
178        pEngine->lastMidiEvent = "NOTE";
179        pEngine->lastMidiEventParameter = msg.m_nData1;
180       
181        bool action = aH->handleAction( mM->getNoteAction( msg.m_nData1 ) );
182       
183        if ( action && Preferences::getInstance()->m_bMidiDiscardNoteAfterAction)
184        {
185                return;
186        }
187
188
189
190       
191
192        bool bPatternSelect = false;
193
194        if ( bIsChannelValid ) {
195                if ( bPatternSelect ) {
196                        int patternNumber = nNote - 36;
197                        INFOLOG( QString( "next pattern = %1" ).arg( patternNumber ) );
198
199                        pEngine->sequencer_setNextPattern( patternNumber, false, false );
200                } else {
201                        static const float fPan_L = 1.0f;
202                        static const float fPan_R = 1.0f;
203
204                        int nInstrument = nNote - 36;
205                        if ( nInstrument < 0 ) {
206                                nInstrument = 0;
207                        }
208                        if ( nInstrument > ( MAX_INSTRUMENTS -1 ) ) {
209                                nInstrument = MAX_INSTRUMENTS - 1;
210                        }
211
212                        pEngine->addRealtimeNote( nInstrument, fVelocity, fPan_L, fPan_R, 0.0, true );
213                }
214        }
215}
216
217
218
219void MidiInput::handleNoteOffMessage( const MidiMessage& msg )
220{
221        INFOLOG( "handleNoteOffMessage" );
222        if ( Preferences::getInstance()->m_bMidiNoteOffIgnore ) {
223                return;
224        }
225
226        Hydrogen *pEngine = Hydrogen::get_instance();
227        Song *pSong = pEngine->getSong();
228
229        int nNote = msg.m_nData1;
230        int nInstrument = nNote - 36;
231        if ( nInstrument < 0 ) {
232                nInstrument = 0;
233        }
234        if ( nInstrument > ( MAX_INSTRUMENTS -1 ) ) {
235                nInstrument = MAX_INSTRUMENTS - 1;
236        }
237        Instrument *pInstr = pSong->get_instrument_list()->get( nInstrument );
238        const unsigned nPosition = 0;
239        const float fVelocity = 0.0f;
240        const float fPan_L = 0.5f;
241        const float fPan_R = 0.5f;
242        const int nLength = -1;
243        const float fPitch = 0.0f;
244        Note *pNewNote = new Note( pInstr, nPosition, fVelocity, fPan_L, fPan_R, nLength, fPitch );
245
246        pEngine->midi_noteOff( pNewNote );
247}
248
249
250
251void MidiInput::handleSysexMessage( const MidiMessage& msg )
252{
253
254        /*
255                General MMC message
256                0       1       2       3       4       5
257                F0      7F      id      6       cmd     247
258
259                cmd:
260                1       stop
261                2       play
262                3       Deferred play
263                4       Fast Forward
264                5       Rewind
265                6       Record strobe (punch in)
266                7       Record exit (punch out)
267                9       Pause
268
269
270                Goto MMC message
271                0       1       2       3       4       5       6       7       8       9       10      11      12
272                240     127     id      6       68      6       1       hr      mn      sc      fr      ff      247
273        */
274       
275       
276        ActionManager * aH = ActionManager::getInstance();
277        MidiMap * mM = MidiMap::getInstance();
278        Hydrogen *pEngine = Hydrogen::get_instance();
279
280        pEngine->lastMidiEventParameter = msg.m_nData1;
281
282
283
284if ( msg.m_sysexData.size() == 6 ) {
285                if (
286                    ( msg.m_sysexData[0] == 0xF0 ) &&
287                    ( msg.m_sysexData[1] == 127 ) &&
288                    ( msg.m_sysexData[2] == 127 ) &&
289                    ( msg.m_sysexData[3] == 6 ) ) {
290
291                       
292                        switch ( msg.m_sysexData[4] ) {
293
294                        case 1: // STOP
295                        {
296                                pEngine->lastMidiEvent = "MMC_STOP";
297                                aH->handleAction(mM->getMMCAction("MMC_STOP"));
298                                break;
299                        }
300
301                        case 2: // PLAY
302                        {
303                                pEngine->lastMidiEvent = "MMC_PLAY";
304                                aH->handleAction(mM->getMMCAction("MMC_PLAY"));
305                                break;
306                        }
307
308                        case 3: //DEFERRED PLAY
309                        {
310                                pEngine->lastMidiEvent = "MMC_PLAY";
311                                aH->handleAction(mM->getMMCAction("MMC_PLAY"));
312                                break;
313                        }
314
315                        case 4: // FAST FWD
316                                pEngine->lastMidiEvent = "MMC_FAST_FWD";
317                                aH->handleAction(mM->getMMCAction("MMC_FAST_FWD"));
318                               
319                                break;
320
321                        case 5: // REWIND
322                                pEngine->lastMidiEvent = "MMC_REWIND";
323                                aH->handleAction(mM->getMMCAction("MMC_REWIND"));
324                                break;
325
326                        case 6: // RECORD STROBE (PUNCH IN)
327                                pEngine->lastMidiEvent = "MMC_RECORD_STROBE";
328                                aH->handleAction(mM->getMMCAction("MMC_RECORD_STROBE"));
329                                break;
330
331                        case 7: // RECORD EXIT (PUNCH OUT)
332                                pEngine->lastMidiEvent = "MMC_RECORD_EXIT";
333                                aH->handleAction(mM->getMMCAction("MMC_RECORD_EXIT"));
334                                break;
335
336                        case 9: //PAUSE
337                                pEngine->lastMidiEvent = "MMC_PAUSE";
338                                aH->handleAction(mM->getMMCAction("MMC_PAUSE"));
339                                break;
340
341                        default:
342                                WARNINGLOG( "Unknown MMC Command" );
343//                                      midiDump( buf, nBytes );
344                        }
345                }
346        } else if ( msg.m_sysexData.size() == 13 ) {
347                ERRORLOG( "MMC GOTO Message not implemented yet" );
348//              midiDump( buf, nBytes );
349                //int id = buf[2];
350                int hr = msg.m_sysexData[7];
351                int mn = msg.m_sysexData[8];
352                int sc = msg.m_sysexData[9];
353                int fr = msg.m_sysexData[10];
354                int ff = msg.m_sysexData[11];
355                char tmp[200];
356                sprintf( tmp, "[handleSysexMessage] GOTO %d:%d:%d:%d:%d", hr, mn, sc, fr, ff );
357                INFOLOG( tmp );
358
359        } else {
360                // sysex dump
361                QString sDump;
362                char tmpChar[64];
363                for ( int i = 0; i < ( int )msg.m_sysexData.size(); ++i ) {
364                        sprintf( tmpChar, "%X ", ( int )msg.m_sysexData[ i ] );
365                        sDump += tmpChar;
366                }
367                WARNINGLOG( QString( "Unknown SysEx message: (%1) [%2]" ).arg( msg.m_sysexData.size() ).arg( sDump ) );
368        }
369}
370
371};
Note: See TracBrowser for help on using the browser.