OSStatus MusicDeviceBase::HandleNoteOff( UInt8 inChannel, UInt8 inNoteNumber, UInt8 inVelocity, UInt32 inStartFrame) { return StopNote (inChannel, inNoteNumber, inStartFrame); }
MMRESULT ProcessShortMidiMessage( DeviceInfo* device_info, DWORD message) { DWORD status; DWORD category; DWORD channel; DWORD data1, data2; status = message & 0x000000FF; /* Deal with running status */ if ( status < MIDI_NOTE_OFF ) { status = device_info->running_status; } /* Ensure the status is sane! */ if ( status < MIDI_NOTE_OFF ) { /* It's garbage, ignore it */ return MMSYSERR_NOERROR; } /* Figure out the message category and channel */ category = status & 0xF0; channel = status & 0x0F; /* we don't use this */ data1 = (message & 0x0000FF00) >> 8; data2 = (message & 0x00FF0000) >> 16; DPRINT("0x%x, %d, %d\n", (int) status, (int) data1, (int) data2); /* Filter drums (which are *usually* on channel 10) */ if ( channel == 10 ) { return MMSYSERR_NOERROR; } /* Pass to the appropriate message handler */ switch ( category ) { case MIDI_NOTE_ON : { PlayNote(device_info, data1, data2); break; } case MIDI_NOTE_OFF : { StopNote(device_info, data1); break; } } return MMSYSERR_NOERROR; }
//-------------------------------------------------------------------------------------------------- void OnKey (char key, bool pressed) { // pressing numbers switches instruments if (pressed) { switch (key) { case '1': g_currentWaveForm = e_waveSine; ReportParams(); return; case '2': g_currentWaveForm = e_waveSaw; ReportParams(); return; case '3': g_currentWaveForm = e_waveSquare; ReportParams(); return; case '4': g_currentWaveForm = e_waveTriangle; ReportParams(); return; case '5': g_currentDelay = e_delayNone; ReportParams(); return; case '6': g_currentDelay = e_delay1; ReportParams(); return; case '7': g_currentDelay = e_delay2; ReportParams(); return; case '8': g_currentDelay = e_delay3; ReportParams(); return; case '9': { std::lock_guard<std::mutex> guard(g_notesMutex); g_notes.push_back(SNote(0.0f, e_sampleCymbals)); return; } case '0': { std::lock_guard<std::mutex> guard(g_notesMutex); g_notes.push_back(SNote(0.0f, e_sampleVoice)); return; } } } // figure out what frequency to play float frequency = 0.0f; switch (key) { // QWERTY row case 'Q': frequency = NoteToFrequency(3, 0); break; case 'W': frequency = NoteToFrequency(3, 1); break; case 'E': frequency = NoteToFrequency(3, 2); break; case 'R': frequency = NoteToFrequency(3, 3); break; case 'T': frequency = NoteToFrequency(3, 4); break; case 'Y': frequency = NoteToFrequency(3, 5); break; case 'U': frequency = NoteToFrequency(3, 6); break; case 'I': frequency = NoteToFrequency(3, 7); break; case 'O': frequency = NoteToFrequency(3, 8); break; case 'P': frequency = NoteToFrequency(3, 9); break; case -37: frequency = NoteToFrequency(3, 10); break; // ASDF row case 'A': frequency = NoteToFrequency(2, 0); break; case 'S': frequency = NoteToFrequency(2, 1); break; case 'D': frequency = NoteToFrequency(2, 2); break; case 'F': frequency = NoteToFrequency(2, 3); break; case 'G': frequency = NoteToFrequency(2, 4); break; case 'H': frequency = NoteToFrequency(2, 5); break; case 'J': frequency = NoteToFrequency(2, 6); break; case 'K': frequency = NoteToFrequency(2, 7); break; case 'L': frequency = NoteToFrequency(2, 8); break; case -70: frequency = NoteToFrequency(2, 9); break; case -34: frequency = NoteToFrequency(2, 10); break; // ZXCV row case 'Z': frequency = NoteToFrequency(1, 0); break; case 'X': frequency = NoteToFrequency(1, 1); break; case 'C': frequency = NoteToFrequency(1, 2); break; case 'V': frequency = NoteToFrequency(1, 3); break; case 'B': frequency = NoteToFrequency(1, 4); break; case 'N': frequency = NoteToFrequency(1, 5); break; case 'M': frequency = NoteToFrequency(1, 6); break; case -68: frequency = NoteToFrequency(1, 7); break; case -66: frequency = NoteToFrequency(1, 8); break; case -65: frequency = NoteToFrequency(1, 9); break; case -95: frequency = NoteToFrequency(1, 10); break; // right shift // left shift = low freq case 16: frequency = NoteToFrequency(0, 5); break; // left shift = low freq case -94: frequency = NoteToFrequency(0, 0); break; default: { return; } } // if releasing a note, we need to find and kill the flute note of the same frequency if (!pressed) { StopNote(frequency); return; } // get a lock on our notes vector and add the new note std::lock_guard<std::mutex> guard(g_notesMutex); g_notes.push_back(SNote(frequency, g_currentWaveForm)); }
MMRESULT PlayNote( DeviceInfo* device_info, UCHAR note, UCHAR velocity) { HANDLE heap = GetProcessHeap(); NoteNode* node; DPRINT("PlayNote\n"); if ( velocity == 0 ) { DPRINT("Zero velocity\n"); /* Velocity zero is effectively a "note off" */ StopNote(device_info, note); } else { /* Start playing the note */ NoteNode* new_node; EnterCriticalSection(&device_lock); node = device_info->note_list; while ( node != NULL ) { #ifndef ALLOW_DUPLICATE_NOTES if ( ( node->note == note ) && ( velocity > 0 ) ) { /* The note is already playing - do nothing */ DPRINT("Duplicate note playback request ignored\n"); LeaveCriticalSection(&device_lock); return MMSYSERR_NOERROR; } #endif node = node->next; } new_node = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(NoteNode)); if ( ! new_node ) { LeaveCriticalSection(&device_lock); return MMSYSERR_NOMEM; } new_node->note = note; new_node->velocity = velocity; /* Prepend to the playing notes list. If exceeding polyphony, remove the oldest note (which will be at the tail.) */ if ( device_info->note_list ) device_info->note_list->previous = new_node; new_node->next = device_info->note_list; new_node->previous = NULL; device_info->note_list = new_node; device_info->playing_notes_count ++; /* if ( device_info->playing_notes_count > POLYPHONY ) { ASSERT(tail_node); DPRINT("Polyphony exceeded\n"); tail_node->previous->next = NULL; HeapFree(heap, 0, tail_node); device_info->playing_notes_count --; } */ LeaveCriticalSection(&device_lock); DPRINT("Note started - now playing %d notes\n", (int) device_info->playing_notes_count); device_info->refresh_notes = TRUE; } #ifndef CONTINUOUS_NOTES ProcessPlayingNotes((PVOID) device_info); #endif return MMSYSERR_NOERROR; }