ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

beepmidi.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.