root/branches/new_fx_rack_and_sample_fun/libs/hydrogen/src/IO/midi_input.cpp @ 785

Revision 785, 10.2 KB (checked in by wolke, 4 years ago)

add a pre delete "beta" function. this function need some more work and testing.

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/audio_engine.h>
31#include <hydrogen/midiMap.h>
32
33namespace H2Core
34{
35
36MidiInput::MidiInput( const QString class_name )
37                : Object( class_name )
38                , m_bActive( false )
39{
40        //INFOLOG( "INIT" );
41       
42}
43
44
45MidiInput::~MidiInput()
46{
47        //INFOLOG( "DESTROY" );
48}
49
50void MidiInput::handleMidiMessage( const MidiMessage& msg )
51{
52        EventQueue::get_instance()->push_event( EVENT_MIDI_ACTIVITY, -1 );
53
54//      infoLog( "[handleMidiMessage]" );
55//      infoLog( "[handleMidiMessage] channel: " + to_string( msg.m_nChannel ) );
56//      infoLog( "[handleMidiMessage] val1: " + to_string( msg.m_nData1 ) );
57//      infoLog( "[handleMidiMessage] val2: " + to_string( msg.m_nData2 ) );
58
59        switch ( msg.m_type ) {
60        case MidiMessage::SYSEX:
61                handleSysexMessage( msg );
62                break;
63
64        case MidiMessage::NOTE_ON:
65                handleNoteOnMessage( msg );
66                break;
67
68        case MidiMessage::NOTE_OFF:
69                handleNoteOffMessage( msg );
70                break;
71
72        case MidiMessage::POLYPHONIC_KEY_PRESSURE:
73                ERRORLOG( "POLYPHONIC_KEY_PRESSURE event not handled yet" );
74                break;
75
76        case MidiMessage::CONTROL_CHANGE:
77                INFOLOG( QString( "[handleMidiMessage] CONTROL_CHANGE Parameter: %1, Value: %2").arg( msg.m_nData1 ).arg( msg.m_nData2 ) );
78                handleControlChangeMessage( msg );
79                break;
80
81        case MidiMessage::PROGRAM_CHANGE:
82                INFOLOG( QString( "[handleMidiMessage] PROGRAM_CHANGE event, seting next pattern to %1" ).arg( msg.m_nData1 ) );
83                Hydrogen::get_instance()->sequencer_setNextPattern(msg.m_nData1, false, false);
84                break;
85
86        case MidiMessage::CHANNEL_PRESSURE:
87                ERRORLOG( "CHANNEL_PRESSURE event not handled yet" );
88                break;
89
90        case MidiMessage::PITCH_WHEEL:
91                ERRORLOG( "PITCH_WHEEL event not handled yet" );
92                break;
93
94        case MidiMessage::SYSTEM_EXCLUSIVE:
95                ERRORLOG( "SYSTEM_EXCLUSIVE event not handled yet" );
96                break;
97
98        case MidiMessage::START:
99                INFOLOG( "START event" );
100                if ( Hydrogen::get_instance()->getState() != STATE_PLAYING ) {
101                        Hydrogen::get_instance()->sequencer_play();
102                }
103                break;
104
105        case MidiMessage::CONTINUE:
106                ERRORLOG( "CONTINUE event not handled yet" );
107                break;
108
109        case MidiMessage::STOP:
110                INFOLOG( "STOP event" );
111                if ( Hydrogen::get_instance()->getState() == STATE_PLAYING ) {
112                        Hydrogen::get_instance()->sequencer_stop();
113                }
114                break;
115
116        case MidiMessage::SONG_POS:
117                ERRORLOG( "SONG_POS event not handled yet" );
118                break;
119
120        case MidiMessage::QUARTER_FRAME:
121                WARNINGLOG( "QUARTER_FRAME event not handled yet" );
122                break;
123
124        case MidiMessage::UNKNOWN:
125                ERRORLOG( "Unknown midi message" );
126                break;
127
128        default:
129                ERRORLOG( QString( "unhandled midi message type: %1" ).arg( msg.m_type ) );
130        }
131}
132
133void MidiInput::handleControlChangeMessage( const MidiMessage& msg )
134{
135        //INFOLOG( QString( "[handleMidiMessage] CONTROL_CHANGE Parameter: %1, Value: %2" ).arg( msg.m_nData1 ).arg( msg.m_nData2 ) );
136       
137        Hydrogen *pEngine = Hydrogen::get_instance();
138        ActionManager * aH = ActionManager::getInstance();
139        MidiMap * mM = MidiMap::getInstance();
140
141        Action * pAction;
142
143        pAction = mM->getCCAction( msg.m_nData1 );
144        pAction->setParameter2( QString::number( msg.m_nData2 ) );
145
146        aH->handleAction( pAction );
147
148        pEngine->lastMidiEvent = "CC";
149        pEngine->lastMidiEventParameter = msg.m_nData1;
150       
151
152}
153
154
155
156void MidiInput::handleNoteOnMessage( const MidiMessage& msg )
157{
158//      INFOLOG( "handleNoteOnMessage" );
159
160
161        int nMidiChannelFilter = Preferences::getInstance()->m_nMidiChannelFilter;
162        int nChannel = msg.m_nChannel;
163        int nNote = msg.m_nData1;
164        float fVelocity = msg.m_nData2 / 127.0;
165
166        if ( fVelocity == 0 ) {
167                handleNoteOffMessage( msg );
168                return;
169        }
170
171
172        bool bIsChannelValid = true;
173        if ( nMidiChannelFilter != -1 ) {
174                bIsChannelValid = ( nChannel == nMidiChannelFilter );
175        }
176
177        ActionManager * aH = ActionManager::getInstance();
178        MidiMap * mM = MidiMap::getInstance();
179        Hydrogen *pEngine = Hydrogen::get_instance();
180
181        pEngine->lastMidiEvent = "NOTE";
182        pEngine->lastMidiEventParameter = msg.m_nData1;
183       
184        bool action = aH->handleAction( mM->getNoteAction( msg.m_nData1 ) );
185       
186        if ( action && Preferences::getInstance()->m_bMidiDiscardNoteAfterAction)
187        {
188                return;
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, false, true, nNote );
213                }
214        }
215        __noteOnTick = pEngine->__getMidiRealtimeNoteTickPosition();
216}
217
218
219
220void MidiInput::handleNoteOffMessage( const MidiMessage& msg )
221{
222//      INFOLOG( "handleNoteOffMessage" );
223        if ( Preferences::getInstance()->m_bMidiNoteOffIgnore ) {
224                return;
225        }
226
227        Hydrogen *pEngine = Hydrogen::get_instance();
228        Song *pSong = pEngine->getSong();
229
230        __noteOffTick = pEngine->getTickPosition();
231        unsigned long notelenght = computeDeltaNoteOnOfftime();
232
233        int nNote = msg.m_nData1;
234        //float fVelocity = msg.m_nData2 / 127.0; //we need this in future to controll release velocity
235        int nInstrument = nNote - 36;
236        if ( nInstrument < 0 ) {
237                nInstrument = 0;
238        }
239        if ( nInstrument > ( MAX_INSTRUMENTS -1 ) ) {
240                nInstrument = MAX_INSTRUMENTS - 1;
241        }
242        Instrument *pInstr = pSong->get_instrument_list()->get( nInstrument );
243
244        float fStep = pow( 1.0594630943593, (nNote -36) );
245        if ( !Preferences::getInstance()->__playselectedinstrument )
246                fStep = 1;
247
248        if ( Preferences::getInstance()->__playselectedinstrument ){
249                nInstrument = pEngine->getSelectedInstrumentNumber();
250                pInstr= pEngine->getSong()->get_instrument_list()->get( pEngine->getSelectedInstrumentNumber());
251        }
252
253        bool use_note_off = AudioEngine::get_instance()->get_sampler()->is_instrument_playing( pInstr );
254        if(use_note_off){
255                if ( Preferences::getInstance()->__playselectedinstrument ){
256                        AudioEngine::get_instance()->get_sampler()->midi_keyboard_note_off( msg.m_nData1 );
257                }else
258                {
259                        Note *offnote = new Note( pInstr,
260                                                0.0,
261                                                0.0,
262                                                0.0,
263                                                0.0,
264                                                -1,
265                                                0 );
266                        offnote->set_noteoff( true );
267                        AudioEngine::get_instance()->get_sampler()->note_on( offnote );
268                }
269                if(Preferences::getInstance()->getRecordEvents())
270                        AudioEngine::get_instance()->get_sampler()->setPlayingNotelenght( pInstr, notelenght * fStep, __noteOnTick );
271        }
272}
273
274
275unsigned long MidiInput::computeDeltaNoteOnOfftime()
276{
277        unsigned long  __notelenghtTicks = __noteOffTick - __noteOnTick;
278        return __notelenghtTicks;
279       
280}
281
282void MidiInput::handleSysexMessage( const MidiMessage& msg )
283{
284
285        /*
286                General MMC message
287                0       1       2       3       4       5
288                F0      7F      id      6       cmd     247
289
290                cmd:
291                1       stop
292                2       play
293                3       Deferred play
294                4       Fast Forward
295                5       Rewind
296                6       Record strobe (punch in)
297                7       Record exit (punch out)
298                9       Pause
299
300
301                Goto MMC message
302                0       1       2       3       4       5       6       7       8       9       10      11      12
303                240     127     id      6       68      6       1       hr      mn      sc      fr      ff      247
304        */
305       
306       
307        ActionManager * aH = ActionManager::getInstance();
308        MidiMap * mM = MidiMap::getInstance();
309        Hydrogen *pEngine = Hydrogen::get_instance();
310
311        pEngine->lastMidiEventParameter = msg.m_nData1;
312
313
314
315if ( msg.m_sysexData.size() == 6 ) {
316                if (
317                    ( msg.m_sysexData[0] == 0xF0 ) &&
318                    ( msg.m_sysexData[1] == 127 ) &&
319                    ( msg.m_sysexData[2] == 127 ) &&
320                    ( msg.m_sysexData[3] == 6 ) ) {
321
322                       
323                        switch ( msg.m_sysexData[4] ) {
324
325                        case 1: // STOP
326                        {
327                                pEngine->lastMidiEvent = "MMC_STOP";
328                                aH->handleAction(mM->getMMCAction("MMC_STOP"));
329                                break;
330                        }
331
332                        case 2: // PLAY
333                        {
334                                pEngine->lastMidiEvent = "MMC_PLAY";
335                                aH->handleAction(mM->getMMCAction("MMC_PLAY"));
336                                break;
337                        }
338
339                        case 3: //DEFERRED PLAY
340                        {
341                                pEngine->lastMidiEvent = "MMC_PLAY";
342                                aH->handleAction(mM->getMMCAction("MMC_PLAY"));
343                                break;
344                        }
345
346                        case 4: // FAST FWD
347                                pEngine->lastMidiEvent = "MMC_FAST_FWD";
348                                aH->handleAction(mM->getMMCAction("MMC_FAST_FWD"));
349                               
350                                break;
351
352                        case 5: // REWIND
353                                pEngine->lastMidiEvent = "MMC_REWIND";
354                                aH->handleAction(mM->getMMCAction("MMC_REWIND"));
355                                break;
356
357                        case 6: // RECORD STROBE (PUNCH IN)
358                                pEngine->lastMidiEvent = "MMC_RECORD_STROBE";
359                                aH->handleAction(mM->getMMCAction("MMC_RECORD_STROBE"));
360                                break;
361
362                        case 7: // RECORD EXIT (PUNCH OUT)
363                                pEngine->lastMidiEvent = "MMC_RECORD_EXIT";
364                                aH->handleAction(mM->getMMCAction("MMC_RECORD_EXIT"));
365                                break;
366
367                        case 9: //PAUSE
368                                pEngine->lastMidiEvent = "MMC_PAUSE";
369                                aH->handleAction(mM->getMMCAction("MMC_PAUSE"));
370                                break;
371
372                        default:
373                                WARNINGLOG( "Unknown MMC Command" );
374//                                      midiDump( buf, nBytes );
375                        }
376                }
377        } else if ( msg.m_sysexData.size() == 13 ) {
378                ERRORLOG( "MMC GOTO Message not implemented yet" );
379//              midiDump( buf, nBytes );
380                //int id = buf[2];
381                int hr = msg.m_sysexData[7];
382                int mn = msg.m_sysexData[8];
383                int sc = msg.m_sysexData[9];
384                int fr = msg.m_sysexData[10];
385                int ff = msg.m_sysexData[11];
386                char tmp[200];
387                sprintf( tmp, "[handleSysexMessage] GOTO %d:%d:%d:%d:%d", hr, mn, sc, fr, ff );
388                INFOLOG( tmp );
389
390        } else {
391                // sysex dump
392                QString sDump = "";
393                char tmpChar[64];
394                for ( int i = 0; i < ( int )msg.m_sysexData.size(); ++i ) {
395                        sprintf( tmpChar, "%X ", ( int )msg.m_sysexData[ i ] );
396                        sDump += tmpChar;
397                }
398                WARNINGLOG( QString( "Unknown SysEx message: (%1) [%2]" ).arg( msg.m_sysexData.size() ).arg( sDump ) );
399        }
400}
401
402};
Note: See TracBrowser for help on using the browser.