Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenbeepmidi.c
Go to the documentation of this file.
00001 /* 00002 BeepMidi :: beep.sys MIDI player 00003 00004 (c) Andrew Greenwood, 2007. 00005 00006 Released as open-source software. You may copy, re-distribute and modify 00007 this software, provided this copyright notice remains intact. 00008 00009 Please see the included README.TXT for more information 00010 00011 HISTORY : 00012 16th January 2007 Started 00013 17th January 2007 Polyphony support and threading added 00014 18th January 2007 Made threading optional, added comments 00015 */ 00016 00017 /* The timeslice to allocate for all playing notes (in milliseconds) */ 00018 #define TIMESLICE_SIZE 60 00019 00020 /* 00021 If this is defined, notes are added to the playing list, even if 00022 they already exist. As a result, the note will sound twice during 00023 each timeslice. Also each note on will require a corresponding note 00024 off event. 00025 */ 00026 #define ALLOW_DUPLICATE_NOTES 00027 00028 /* 00029 The maximum number of notes that may be playing at any one time. 00030 Higher values result in a messier sound as all the frequencies get 00031 mashed together. Do not set this below 2. Recommended = 4 00032 */ 00033 #define POLYPHONY 3 00034 00035 /* 00036 Define CONTINUOUS_NOTES to perform note playback in a separate thread. 00037 This was originally the intended behaviour, but after experimentation 00038 doesn't sound as good for MIDI files which have a lot going on. If not 00039 defined, all playing notes are output in sequence as a new note starts. 00040 */ 00041 #define CONTINUOUS_NOTES 00042 00043 #define WIN32_NO_STATUS 00044 #include <windows.h> 00045 #define NTOS_MODE_USER 00046 #include <ndk/iofuncs.h> 00047 #include <ndk/obfuncs.h> 00048 #include <ndk/rtlfuncs.h> 00049 #include <stdio.h> 00050 #include <ntddbeep.h> 00051 #include <math.h> 00052 00053 #include <mmddk.h> 00054 #include <mmsystem.h> 00055 00056 /*#define DPRINT printf*/ 00057 #define DPRINT FakePrintf 00058 00059 /* A few MIDI command categories */ 00060 #define MIDI_NOTE_OFF 0x80 00061 #define MIDI_NOTE_ON 0x90 00062 #define MIDI_CONTROL_CHANGE 0xB0 00063 #define MIDI_PROGRAM 0xC0 00064 #define MIDI_PITCH_BEND 0xE0 00065 #define MIDI_SYSTEM 0xFF 00066 00067 /* Specific commands */ 00068 #define MIDI_RESET 0xFF 00069 00070 00071 typedef struct _NoteNode 00072 { 00073 struct _NoteNode* next; 00074 struct _NoteNode* previous; 00075 00076 UCHAR note; 00077 UCHAR velocity; /* 0 is note-off */ 00078 } NoteNode; 00079 00080 typedef struct _DeviceInfo 00081 { 00082 HDRVR mme_handle; 00083 HANDLE kernel_device; 00084 00085 DWORD callback; 00086 DWORD instance; 00087 DWORD flags; 00088 00089 UCHAR running_status; 00090 00091 DWORD playing_notes_count; 00092 NoteNode* note_list; 00093 BOOL refresh_notes; 00094 00095 HANDLE thread_handle; 00096 BOOL terminate_thread; 00097 HANDLE thread_termination_complete; 00098 } DeviceInfo; 00099 00100 DeviceInfo* the_device; 00101 CRITICAL_SECTION device_lock; 00102 00103 void 00104 FakePrintf(char* str, ...) 00105 { 00106 /* Just to shut the compiler up */ 00107 } 00108 00109 00110 /* 00111 This is designed to be treated as a thread, however it behaves as a 00112 normal function if CONTINUOUS_NOTES is not defined. 00113 */ 00114 00115 DWORD WINAPI 00116 ProcessPlayingNotes( 00117 LPVOID parameter) 00118 { 00119 DeviceInfo* device_info = (DeviceInfo*) parameter; 00120 NTSTATUS status; 00121 IO_STATUS_BLOCK io_status_block; 00122 DWORD arp_notes; 00123 00124 DPRINT("Note processing started\n"); 00125 00126 /* We lock the note list only while accessing it */ 00127 00128 #ifdef CONTINUOUS_NOTES 00129 while ( ! device_info->terminate_thread ) 00130 #endif 00131 { 00132 NoteNode* node; 00133 00134 /* Number of notes being arpeggiated */ 00135 arp_notes = 1; 00136 00137 EnterCriticalSection(&device_lock); 00138 00139 /* Calculate how much time to allocate to each playing note */ 00140 00141 DPRINT("%d notes active\n", (int) device_info->playing_notes_count); 00142 00143 node = device_info->note_list; 00144 00145 while ( ( node != NULL ) && ( arp_notes <= POLYPHONY ) ) 00146 { 00147 BEEP_SET_PARAMETERS beep_data; 00148 DWORD actually_playing = 0; 00149 00150 double frequency = node->note; 00151 00152 DPRINT("playing..\n"); 00153 00154 frequency = frequency / 12; 00155 frequency = pow(2, frequency); 00156 frequency = 8.1758 * frequency; 00157 00158 if (device_info->playing_notes_count > POLYPHONY) 00159 actually_playing = POLYPHONY; 00160 else 00161 actually_playing = device_info->playing_notes_count; 00162 00163 DPRINT("Frequency %f\n", frequency); 00164 00165 // TODO 00166 beep_data.Frequency = (DWORD) frequency; 00167 beep_data.Duration = TIMESLICE_SIZE / actually_playing; /* device_info->playing_notes_count; */ 00168 00169 status = NtDeviceIoControlFile(device_info->kernel_device, 00170 NULL, 00171 NULL, 00172 NULL, 00173 &io_status_block, 00174 IOCTL_BEEP_SET, 00175 &beep_data, 00176 sizeof(BEEP_SET_PARAMETERS), 00177 NULL, 00178 0); 00179 00180 if ( ! NT_SUCCESS(status) ) 00181 { 00182 DPRINT("ERROR %d\n", (int) GetLastError()); 00183 } 00184 00185 SleepEx(beep_data.Duration, TRUE); 00186 00187 if ( device_info->refresh_notes ) 00188 { 00189 device_info->refresh_notes = FALSE; 00190 break; 00191 } 00192 00193 arp_notes ++; 00194 node = node->next; 00195 } 00196 00197 LeaveCriticalSection(&device_lock); 00198 } 00199 00200 #ifdef CONTINUOUS_NOTES 00201 SetEvent(device_info->thread_termination_complete); 00202 #endif 00203 00204 return 0; 00205 } 00206 00207 00208 /* 00209 Fills a MIDIOUTCAPS structure with information about our device. 00210 */ 00211 00212 MMRESULT 00213 GetDeviceCapabilities( 00214 MIDIOUTCAPS* caps) 00215 { 00216 /* These are ignored for now */ 00217 caps->wMid = 0; 00218 caps->wPid = 0; 00219 00220 caps->vDriverVersion = 0x0100; 00221 00222 memset(caps->szPname, 0, sizeof(caps->szPname)); 00223 memcpy(caps->szPname, L"PC speaker\0", strlen("PC speaker\0") * 2); 00224 00225 caps->wTechnology = MOD_SQSYNTH; 00226 00227 caps->wVoices = 1; /* We only have one voice */ 00228 caps->wNotes = POLYPHONY; 00229 caps->wChannelMask = 0xFFBF; /* Ignore channel 10 */ 00230 00231 caps->dwSupport = 0; 00232 00233 return MMSYSERR_NOERROR; 00234 } 00235 00236 00237 /* 00238 Helper function that just simplifies calling the application making use 00239 of us. 00240 */ 00241 00242 BOOL 00243 CallClient( 00244 DeviceInfo* device_info, 00245 DWORD_PTR message, 00246 DWORD_PTR parameter1, 00247 DWORD_PTR parameter2) 00248 { 00249 DPRINT("Calling client - callback 0x%x mmhandle 0x%x\n", device_info->callback, device_info->mme_handle); 00250 return DriverCallback(device_info->callback, 00251 HIWORD(device_info->flags), 00252 device_info->mme_handle, 00253 message, 00254 device_info->instance, 00255 parameter1, 00256 parameter2); 00257 00258 } 00259 00260 00261 /* 00262 Open the kernel-mode device and allocate resources. This opens the 00263 BEEP.SYS kernel device. 00264 */ 00265 00266 MMRESULT 00267 OpenDevice( 00268 DeviceInfo** private_data, 00269 MIDIOPENDESC* open_desc, 00270 DWORD flags) 00271 { 00272 NTSTATUS status; 00273 HANDLE heap; 00274 HANDLE kernel_device; 00275 UNICODE_STRING beep_device_name; 00276 OBJECT_ATTRIBUTES attribs; 00277 IO_STATUS_BLOCK status_block; 00278 00279 /* One at a time.. */ 00280 if ( the_device ) 00281 { 00282 DPRINT("Already allocated\n"); 00283 return MMSYSERR_ALLOCATED; 00284 } 00285 00286 /* Make the device name into a unicode string and open it */ 00287 00288 RtlInitUnicodeString(&beep_device_name, 00289 L"\\Device\\Beep"); 00290 00291 InitializeObjectAttributes(&attribs, 00292 &beep_device_name, 00293 0, 00294 NULL, 00295 NULL); 00296 00297 status = NtCreateFile(&kernel_device, 00298 FILE_READ_DATA | FILE_WRITE_DATA, 00299 &attribs, 00300 &status_block, 00301 NULL, 00302 0, 00303 FILE_SHARE_READ | FILE_SHARE_WRITE, 00304 FILE_OPEN_IF, 00305 0, 00306 NULL, 00307 0); 00308 00309 if ( ! NT_SUCCESS(status) ) 00310 { 00311 DPRINT("Could not connect to BEEP device - %d\n", (int) GetLastError()); 00312 return MMSYSERR_ERROR; 00313 } 00314 00315 DPRINT("Opened!\n"); 00316 00317 /* Allocate and initialize the device info */ 00318 00319 heap = GetProcessHeap(); 00320 00321 the_device = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(DeviceInfo)); 00322 00323 if ( ! the_device ) 00324 { 00325 DPRINT("Out of memory\n"); 00326 return MMSYSERR_NOMEM; 00327 } 00328 00329 /* Initialize */ 00330 the_device->kernel_device = kernel_device; 00331 the_device->playing_notes_count = 0; 00332 the_device->note_list = NULL; 00333 the_device->thread_handle = 0; 00334 the_device->terminate_thread = FALSE; 00335 the_device->running_status = 0; 00336 00337 // TODO 00338 the_device->mme_handle = (HDRVR) open_desc->hMidi; 00339 the_device->callback = open_desc->dwCallback; 00340 the_device->instance = open_desc->dwInstance; 00341 the_device->flags = flags; 00342 00343 /* Store the pointer in the user data */ 00344 *private_data = the_device; 00345 00346 /* This is threading-related code */ 00347 #ifdef CONTINUOUS_NOTES 00348 the_device->thread_termination_complete = CreateEvent(NULL, FALSE, FALSE, NULL); 00349 00350 if ( ! the_device->thread_termination_complete ) 00351 { 00352 DPRINT("CreateEvent failed\n"); 00353 HeapFree(heap, 0, the_device); 00354 return MMSYSERR_NOMEM; 00355 } 00356 00357 the_device->thread_handle = CreateThread(NULL, 00358 0, 00359 ProcessPlayingNotes, 00360 (PVOID) the_device, 00361 0, 00362 NULL); 00363 00364 if ( ! the_device->thread_handle ) 00365 { 00366 DPRINT("CreateThread failed\n"); 00367 CloseHandle(the_device->thread_termination_complete); 00368 HeapFree(heap, 0, the_device); 00369 return MMSYSERR_NOMEM; 00370 } 00371 #endif 00372 00373 /* Now we call the client application to say the device is open */ 00374 DPRINT("Sending MOM_OPEN\n"); 00375 DPRINT("Success? %d\n", (int) CallClient(the_device, MOM_OPEN, 0, 0)); 00376 00377 return MMSYSERR_NOERROR; 00378 } 00379 00380 00381 /* 00382 Close the kernel-mode device. 00383 */ 00384 00385 MMRESULT 00386 CloseDevice(DeviceInfo* device_info) 00387 { 00388 HANDLE heap = GetProcessHeap(); 00389 00390 /* If we're working in threaded mode we need to wait for thread to die */ 00391 #ifdef CONTINUOUS_NOTES 00392 the_device->terminate_thread = TRUE; 00393 00394 WaitForSingleObject(the_device->thread_termination_complete, INFINITE); 00395 00396 CloseHandle(the_device->thread_termination_complete); 00397 #endif 00398 00399 /* Let the client application know the device is closing */ 00400 DPRINT("Sending MOM_CLOSE\n"); 00401 CallClient(device_info, MOM_CLOSE, 0, 0); 00402 00403 NtClose(device_info->kernel_device); 00404 00405 /* Free resources */ 00406 HeapFree(heap, 0, device_info); 00407 00408 the_device = NULL; 00409 00410 return MMSYSERR_NOERROR; 00411 } 00412 00413 00414 /* 00415 Removes a note from the playing notes list. If the note is not playing, 00416 we just pretend nothing happened. 00417 */ 00418 00419 MMRESULT 00420 StopNote( 00421 DeviceInfo* device_info, 00422 UCHAR note) 00423 { 00424 HANDLE heap = GetProcessHeap(); 00425 NoteNode* node; 00426 NoteNode* prev_node = NULL; 00427 00428 DPRINT("StopNote\n"); 00429 00430 EnterCriticalSection(&device_lock); 00431 00432 node = device_info->note_list; 00433 00434 while ( node != NULL ) 00435 { 00436 if ( node->note == note ) 00437 { 00438 /* Found the note - just remove the node from the list */ 00439 00440 DPRINT("Stopping note %d\n", (int) node->note); 00441 00442 if ( prev_node != NULL ) 00443 prev_node->next = node->next; 00444 else 00445 device_info->note_list = node->next; 00446 00447 HeapFree(heap, 0, node); 00448 00449 device_info->playing_notes_count --; 00450 00451 DPRINT("Note stopped - now playing %d notes\n", (int) device_info->playing_notes_count); 00452 00453 LeaveCriticalSection(&device_lock); 00454 device_info->refresh_notes = TRUE; 00455 00456 return MMSYSERR_NOERROR; 00457 } 00458 00459 prev_node = node; 00460 node = node->next; 00461 } 00462 00463 LeaveCriticalSection(&device_lock); 00464 00465 /* Hmm, a good idea? */ 00466 #ifndef CONTINUOUS_NOTES 00467 ProcessPlayingNotes((PVOID) device_info); 00468 #endif 00469 00470 return MMSYSERR_NOERROR; 00471 } 00472 00473 00474 /* 00475 Adds a note to the playing notes list. If the note is already playing, 00476 the definition of ALLOW_DUPLICATE_NOTES determines if an existing note 00477 may be duplicated. Otherwise, duplicate notes are ignored. 00478 */ 00479 00480 MMRESULT 00481 PlayNote( 00482 DeviceInfo* device_info, 00483 UCHAR note, 00484 UCHAR velocity) 00485 { 00486 HANDLE heap = GetProcessHeap(); 00487 00488 NoteNode* node; 00489 00490 DPRINT("PlayNote\n"); 00491 00492 if ( velocity == 0 ) 00493 { 00494 DPRINT("Zero velocity\n"); 00495 00496 /* Velocity zero is effectively a "note off" */ 00497 StopNote(device_info, note); 00498 } 00499 else 00500 { 00501 /* Start playing the note */ 00502 NoteNode* new_node; 00503 00504 EnterCriticalSection(&device_lock); 00505 00506 node = device_info->note_list; 00507 00508 while ( node != NULL ) 00509 { 00510 #ifndef ALLOW_DUPLICATE_NOTES 00511 if ( ( node->note == note ) && ( velocity > 0 ) ) 00512 { 00513 /* The note is already playing - do nothing */ 00514 DPRINT("Duplicate note playback request ignored\n"); 00515 LeaveCriticalSection(&device_lock); 00516 return MMSYSERR_NOERROR; 00517 } 00518 #endif 00519 00520 node = node->next; 00521 } 00522 00523 new_node = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(NoteNode)); 00524 00525 if ( ! new_node ) 00526 { 00527 LeaveCriticalSection(&device_lock); 00528 return MMSYSERR_NOMEM; 00529 } 00530 00531 new_node->note = note; 00532 new_node->velocity = velocity; 00533 00534 /* 00535 Prepend to the playing notes list. If exceeding polyphony, 00536 remove the oldest note (which will be at the tail.) 00537 */ 00538 00539 if ( device_info->note_list ) 00540 device_info->note_list->previous = new_node; 00541 00542 new_node->next = device_info->note_list; 00543 new_node->previous = NULL; 00544 00545 device_info->note_list = new_node; 00546 device_info->playing_notes_count ++; 00547 00548 /* 00549 if ( device_info->playing_notes_count > POLYPHONY ) 00550 { 00551 ASSERT(tail_node); 00552 00553 DPRINT("Polyphony exceeded\n"); 00554 00555 tail_node->previous->next = NULL; 00556 00557 HeapFree(heap, 0, tail_node); 00558 00559 device_info->playing_notes_count --; 00560 } 00561 */ 00562 00563 LeaveCriticalSection(&device_lock); 00564 00565 DPRINT("Note started - now playing %d notes\n", (int) device_info->playing_notes_count); 00566 device_info->refresh_notes = TRUE; 00567 } 00568 00569 #ifndef CONTINUOUS_NOTES 00570 ProcessPlayingNotes((PVOID) device_info); 00571 #endif 00572 00573 return MMSYSERR_NOERROR; 00574 } 00575 00576 /* 00577 Decipher a short MIDI message (which is a MIDI message packed into a DWORD.) 00578 This will set "running status", but does not take this into account when 00579 processing messages (is this necessary?) 00580 */ 00581 00582 MMRESULT 00583 ProcessShortMidiMessage( 00584 DeviceInfo* device_info, 00585 DWORD message) 00586 { 00587 DWORD status; 00588 00589 DWORD category; 00590 DWORD channel; 00591 DWORD data1, data2; 00592 00593 status = message & 0x000000FF; 00594 00595 /* Deal with running status */ 00596 00597 if ( status < MIDI_NOTE_OFF ) 00598 { 00599 status = device_info->running_status; 00600 } 00601 00602 /* Ensure the status is sane! */ 00603 00604 if ( status < MIDI_NOTE_OFF ) 00605 { 00606 /* It's garbage, ignore it */ 00607 return MMSYSERR_NOERROR; 00608 } 00609 00610 /* Figure out the message category and channel */ 00611 00612 category = status & 0xF0; 00613 channel = status & 0x0F; /* we don't use this */ 00614 00615 data1 = (message & 0x0000FF00) >> 8; 00616 data2 = (message & 0x00FF0000) >> 16; 00617 00618 DPRINT("0x%x, %d, %d\n", (int) status, (int) data1, (int) data2); 00619 00620 /* Filter drums (which are *usually* on channel 10) */ 00621 if ( channel == 10 ) 00622 { 00623 return MMSYSERR_NOERROR; 00624 } 00625 00626 /* Pass to the appropriate message handler */ 00627 00628 switch ( category ) 00629 { 00630 case MIDI_NOTE_ON : 00631 { 00632 PlayNote(device_info, data1, data2); 00633 break; 00634 } 00635 00636 case MIDI_NOTE_OFF : 00637 { 00638 StopNote(device_info, data1); 00639 break; 00640 } 00641 } 00642 00643 return MMSYSERR_NOERROR; 00644 } 00645 00646 00647 #define PACK_MIDI(b1, b2, b3) \ 00648 ((b3 * 65536) + (b2 * 256) + b1); 00649 00650 00651 /* 00652 Processes a "long" MIDI message (ie, a MIDI message contained within a 00653 buffer.) This is intended for supporting SysEx data, or blocks of MIDI 00654 events. However in our case we're only interested in short MIDI messages, 00655 so we scan the buffer, and each time we encounter a valid status byte 00656 we start recording it as a new event. Once 3 bytes or a new status is 00657 received, the event is passed to the short message handler. 00658 */ 00659 00660 MMRESULT 00661 ProcessLongMidiMessage( 00662 DeviceInfo* device_info, 00663 MIDIHDR* header) 00664 { 00665 unsigned int index = 0; 00666 UCHAR* midi_bytes = (UCHAR*) header->lpData; 00667 00668 unsigned int msg_index = 0; 00669 UCHAR msg[3]; 00670 00671 /* Initialize the buffer */ 00672 msg[0] = msg[1] = msg[2] = 0; 00673 00674 if ( ! ( header->dwFlags & MHDR_PREPARED ) ) 00675 { 00676 DPRINT("Not prepared!\n"); 00677 return MIDIERR_UNPREPARED; 00678 } 00679 00680 DPRINT("Processing %d bytes of MIDI\n", (int) header->dwBufferLength); 00681 00682 while ( index < header->dwBufferLength ) 00683 { 00684 /* New status byte? ( = new event) */ 00685 if ( midi_bytes[index] & 0x80 ) 00686 { 00687 DWORD short_msg; 00688 00689 /* Deal with the existing event */ 00690 00691 if ( msg[0] & 0x80 ) 00692 { 00693 short_msg = PACK_MIDI(msg[0], msg[1], msg[2]); 00694 00695 DPRINT("Complete msg is 0x%x %d %d\n", (int) msg[0], (int) msg[1], (int) msg[2]); 00696 ProcessShortMidiMessage(device_info, short_msg); 00697 } 00698 00699 /* Set new running status and start recording the event */ 00700 DPRINT("Set new running status\n"); 00701 device_info->running_status = midi_bytes[index]; 00702 msg[0] = midi_bytes[index]; 00703 msg_index = 1; 00704 } 00705 00706 /* Unexpected data byte? ( = re-use previous status) */ 00707 else if ( msg_index == 0 ) 00708 { 00709 if ( device_info->running_status & 0x80 ) 00710 { 00711 DPRINT("Retrieving running status\n"); 00712 msg[0] = device_info->running_status; 00713 msg[1] = midi_bytes[index]; 00714 msg_index = 2; 00715 } 00716 else 00717 DPRINT("garbage\n"); 00718 } 00719 00720 /* Expected data ( = append to message until buffer full) */ 00721 else 00722 { 00723 DPRINT("Next byte...\n"); 00724 msg[msg_index] = midi_bytes[index]; 00725 msg_index ++; 00726 00727 if ( msg_index > 2 ) 00728 { 00729 DWORD short_msg; 00730 00731 short_msg = PACK_MIDI(msg[0], msg[1], msg[2]); 00732 00733 DPRINT("Complete msg is 0x%x %d %d\n", (int) msg[0], (int) msg[1], (int) msg[2]); 00734 ProcessShortMidiMessage(device_info, short_msg); 00735 00736 /* Reinit */ 00737 msg_index = 0; 00738 msg[0] = msg[1] = msg[2] = 0; 00739 } 00740 } 00741 00742 index ++; 00743 } 00744 00745 /* 00746 We're meant to clear MHDR_DONE and set MHDR_INQUEUE but since we 00747 deal with everything here and now we might as well just say so. 00748 */ 00749 header->dwFlags |= MHDR_DONE; 00750 header->dwFlags &= ~ MHDR_INQUEUE; 00751 00752 DPRINT("Success? %d\n", CallClient(the_device, MOM_DONE, (DWORD_PTR) header, 0)); 00753 00754 return MMSYSERR_NOERROR; 00755 } 00756 00757 00758 /* 00759 Exported function that receives messages from WINMM (the MME API.) 00760 */ 00761 00762 MMRESULT 00763 FAR PASCAL 00764 modMessage( 00765 UINT device_id, 00766 UINT message, 00767 DWORD_PTR private_data, 00768 DWORD_PTR parameter1, 00769 DWORD_PTR parameter2) 00770 { 00771 switch ( message ) 00772 { 00773 case MODM_GETNUMDEVS : 00774 { 00775 /* Only one internal PC speaker device (and even that's too much) */ 00776 DPRINT("MODM_GETNUMDEVS\n"); 00777 return 1; 00778 } 00779 00780 case MODM_GETDEVCAPS : 00781 { 00782 DPRINT("MODM_GETDEVCAPS\n"); 00783 return GetDeviceCapabilities((MIDIOUTCAPS*) parameter1); 00784 } 00785 00786 case MODM_OPEN : 00787 { 00788 DPRINT("MODM_OPEN\n"); 00789 00790 return OpenDevice((DeviceInfo**) private_data, 00791 (MIDIOPENDESC*) parameter1, 00792 parameter2); 00793 } 00794 00795 case MODM_CLOSE : 00796 { 00797 DPRINT("MODM_CLOSE\n"); 00798 return CloseDevice((DeviceInfo*) private_data); 00799 } 00800 00801 case MODM_DATA : 00802 { 00803 return ProcessShortMidiMessage((DeviceInfo*) private_data, parameter1); 00804 } 00805 00806 case MODM_PREPARE : 00807 { 00808 /* We don't bother with this */ 00809 MIDIHDR* hdr = (MIDIHDR*) parameter1; 00810 hdr->dwFlags |= MHDR_PREPARED; 00811 return MMSYSERR_NOERROR; 00812 } 00813 00814 case MODM_UNPREPARE : 00815 { 00816 MIDIHDR* hdr = (MIDIHDR*) parameter1; 00817 hdr->dwFlags &= ~MHDR_PREPARED; 00818 return MMSYSERR_NOERROR; 00819 } 00820 00821 case MODM_LONGDATA : 00822 { 00823 DPRINT("LONGDATA\n"); 00824 return ProcessLongMidiMessage((DeviceInfo*) private_data, (MIDIHDR*) parameter1); 00825 } 00826 00827 case MODM_RESET : 00828 { 00829 /* TODO */ 00830 break; 00831 } 00832 } 00833 00834 DPRINT("Not supported %d\n", message); 00835 00836 return MMSYSERR_NOTSUPPORTED; 00837 } 00838 00839 00840 /* 00841 Driver entrypoint. 00842 */ 00843 00844 LONG 00845 FAR PASCAL 00846 DriverProc( 00847 DWORD driver_id, 00848 HDRVR driver_handle, 00849 UINT message, 00850 LONG parameter1, 00851 LONG parameter2) 00852 { 00853 switch ( message ) 00854 { 00855 case DRV_LOAD : 00856 DPRINT("DRV_LOAD\n"); 00857 the_device = NULL; 00858 return 1L; 00859 00860 case DRV_FREE : 00861 DPRINT("DRV_FREE\n"); 00862 return 1L; 00863 00864 case DRV_OPEN : 00865 DPRINT("DRV_OPEN\n"); 00866 InitializeCriticalSection(&device_lock); 00867 return 1L; 00868 00869 case DRV_CLOSE : 00870 DPRINT("DRV_CLOSE\n"); 00871 return 1L; 00872 00873 case DRV_ENABLE : 00874 DPRINT("DRV_ENABLE\n"); 00875 return 1L; 00876 00877 case DRV_DISABLE : 00878 DPRINT("DRV_DISABLE\n"); 00879 return 1L; 00880 00881 /* 00882 We don't provide configuration capabilities. This used to be 00883 for things like I/O port, IRQ, DMA settings, etc. 00884 */ 00885 00886 case DRV_QUERYCONFIGURE : 00887 DPRINT("DRV_QUERYCONFIGURE\n"); 00888 return 0L; 00889 00890 case DRV_CONFIGURE : 00891 DPRINT("DRV_CONFIGURE\n"); 00892 return 0L; 00893 00894 case DRV_INSTALL : 00895 DPRINT("DRV_INSTALL\n"); 00896 return DRVCNF_RESTART; 00897 }; 00898 00899 DPRINT("???\n"); 00900 00901 return DefDriverProc(driver_id, 00902 driver_handle, 00903 message, 00904 parameter1, 00905 parameter2); 00906 } Generated on Sat May 26 2012 04:21:24 for ReactOS by
1.7.6.1
|