aboutsummaryrefslogtreecommitdiff
path: root/pd/portmidi/pm_win/README_WIN.txt
diff options
context:
space:
mode:
Diffstat (limited to 'pd/portmidi/pm_win/README_WIN.txt')
-rw-r--r--pd/portmidi/pm_win/README_WIN.txt134
1 files changed, 121 insertions, 13 deletions
diff --git a/pd/portmidi/pm_win/README_WIN.txt b/pd/portmidi/pm_win/README_WIN.txt
index df120e96..3fe5ee41 100644
--- a/pd/portmidi/pm_win/README_WIN.txt
+++ b/pd/portmidi/pm_win/README_WIN.txt
@@ -20,7 +20,8 @@ intended for debugging, especially in a console application. The Debug
version enables some extra error checking and outputs some text as well
as a prompt to type ENTER so that you don't lose any debugging text when
the program exits. You can turn off this extra debugging info by taking
-out the compile-time definition for DEBUG. This debugging version also
+out the compile-time definition for DEBUG. (But leave _DEBUG, which I
+think is important for compiling in Debug mode.) This debugging version also
defines PM_CHECK_ERRORS, which forces a check for error return codes from
every call to PortMidi. You can disable this checking (especially if you
want to handle error codes in your own way) by removing PM_CHECK_ERRORS
@@ -45,9 +46,9 @@ TO INSTALL PORTMIDI:
TO COMPILE PORTMIDI:
=============================================================================
-3) go to this directory
+3) cd to or open the portmidi directory
-4) click on the portmidi.dsw workspace
+4) start or click on the portmidi.dsw workspace
5) the following projects exist within this workspace:
- portmidi (the PortMidi library)
@@ -60,18 +61,16 @@ TO COMPILE PORTMIDI:
- latency (uses porttime to measure system latency)
6) verify that all project settings are for Win32 Debug release:
- - hit Alt-F7
+ - type Alt-F7
- highlight all three projects in left part of Project Settings window;
- "Settings For" should say "Win32 Debug"
-7) set pm_dll as the active project (e.g. Project->Select Active Project)
+7) use Build->Batch Build ... to build everything in the project
-8) use Build->Batch Build ... to build everything in the project
-
-9) The settings for these projects were distributed in the zip file, so
+8) The settings for these projects were distributed in the zip file, so
compile should just work.
-10) IMPORTANT! PortMidi uses a DLL, pm_dll.dll, but there is no simple way
+9) IMPORTANT! PortMidi uses a DLL, pm_dll.dll, but there is no simple way
to set up projects to use pm_dll. THEREFORE, you need to copy DLLs
as follows (you can do this with <...>\portmidi\pm_win\copy-dll.bat):
copy <...>\portmidi\pm_win\Debug\pm_dll.dll to:
@@ -94,13 +93,13 @@ TO COMPILE PORTMIDI:
application using PortMidi. The release DLL is about 40KB. This will
ensure that the application uses the correct DLL.
-11) run test project; use the menu that shows up from the command prompt to
+10) run test project; use the menu that shows up from the command prompt to
test that portMidi works on your system. tests include:
- verify midi output works
- verify midi input works
- verify midi input w/midi thru works
-12) run other projects if you wish: sysex, latency, and midithread
+11) run other projects if you wish: sysex, latency, midithread, mm, qtest
============================================================================
TO CREATE YOUR OWN PORTMIDI CLIENT APPLICATION:
@@ -179,5 +178,114 @@ To open input:
- return
- return
-
-
+SYSEX HANDLING -- the most complex, least exercised, and therefore most
+ buggy part of PortMidi (but maybe bugs are finally gone)
+
+There are three cases: simple output, stream output, input
+Each must deal with:
+ 1. Buffer Initialization (creating buffers)
+ 2. Buffer Allocation (finding a free buffer)
+ 3. Buffer Fill (putting bytes in the buffer)
+ 4. Buffer Preparation (midiOutPrepare, etc.)
+ 5. Buffer Send (to Midi device)
+ 6. Buffer Receive (in callback)
+ 7. Buffer Empty (removing bytes from buffer)
+ 8. Buffer Free (returning to the buffer pool)
+ 9. Buffer Finalization (returning to heap)
+
+Here's how simple output handles sysex:
+ 1. Buffer Initialization (creating buffers)
+ allocated when code tries to write first byte to a buffer
+ the test is "if (!m->sysex_buffers[0]) { ... }"
+ this field is initialized to NULL when device is opened
+ the size is SYSEX_BYTES_PER_BUFFER
+ allocate_sysex_buffers() does the initialization
+ note that the actual size of the allocation includes
+ additional space for a MIDIEVENT (3 longs) which are
+ not used in this case
+ 2. Buffer Allocation (finding a free buffer)
+ see get_free_sysex_buffer()
+ cycle through m->sysex_buffers[] using m->next_sysex_buffer
+ to determine where to look next
+ if nothing is found, wait by blocking on m->sysex_buffer_signal
+ this is signaled by the callback every time a message is
+ received
+ 3. Buffer Fill (putting bytes in the buffer)
+ essentially a state machine approach
+ hdr->dwBytesRecorded is a position in message pointed to by m->hdr
+ keep appending bytes until dwBytesRecorded >= SYSEX_BYTES_PER_BUFFER
+ then send the message, reseting the state to initial values
+ 4. Buffer Preparation (midiOutPrepare, etc.)
+ just before sending in winmm_end_sysex()
+ 5. Buffer Send (to Midi device)
+ message is padded with zero at end (since extra space was allocated
+ this is ok) -- the zero works around a bug in (an old version of)
+ MIDI YOKE drivers
+ dwBufferLength gets dwBytesRecorded, and dwBytesRecorded gets 0
+ uses midiOutLongMsg()
+ 6. Buffer Receive (in callback)
+ 7. Buffer Empty (removing bytes from buffer)
+ not applicable for output
+ 8. Buffer Free (returning to the buffer pool)
+ unprepare message to indicate that it is free
+ SetEvent on m->buffer_signal in case client is waiting
+ 9. Buffer Finalization (returning to heap)
+ when device is closed, winmm_out_delete frees all sysex buffers
+
+Here's how stream output handles sysex:
+ 1. Buffer Initialization (creating buffers)
+ same code as simple output (see above)
+ 2. Buffer Allocation (finding a free buffer)
+ same code as simple output (see above)
+ 3. Buffer Fill (putting bytes in the buffer)
+ essentially a state machine approach
+ m->dwBytesRecorded is a position in message
+ keep appending bytes until buffer is full (one byte to spare)
+ 4. Buffer Preparation (midiOutPrepare, etc.)
+ done before sending message
+ dwBytesRecorded and dwBufferLength are set in winmm_end_sysex
+ 5. Buffer Send (to Midi device)
+ uses midiStreamOutMsg()
+ 6. Buffer Receive (in callback)
+ 7. Buffer Empty (removing bytes from buffer)
+ not applicable for output
+ 8. Buffer Free (returning to the buffer pool)
+ unprepare message to indicate that it is free
+ SetEvent on m->buffer_signal in case client is waiting
+ 9. Buffer Finalization (returning to heap)
+ when device is closed, winmm_out_delete frees all sysex buffers
+
+
+Here's how input handles sysex:
+ 1. Buffer Initialization (creating buffers)
+ two buffers are allocated in winmm_in_open
+ 2. Buffer Allocation (finding a free buffer)
+ same code as simple output (see above)
+ 3. Buffer Fill (putting bytes in the buffer)
+ not applicable for input
+ 4. Buffer Preparation (midiOutPrepare, etc.)
+ done before sending message -- in winmm_in_open and in callback
+ 5. Buffer Send (to Midi device)
+ uses midiInAddbuffer in allocate_sysex_input_buffer (called from
+ winmm_in_open) and callback
+ 6. Buffer Receive (in callback)
+ 7. Buffer Empty (removing bytes from buffer)
+ done without pause in loop in callback
+ 8. Buffer Free (returning to the buffer pool)
+ done by midiInAddBuffer in callback, no pointer to buffers
+ is retained except by device
+ 9. Buffer Finalization (returning to heap)
+ when device is closed, empty buffers are delivered to callback,
+ which frees them
+
+IMPORTANT: In addition to the above, PortMidi now has
+"shortcuts" to optimize the transfer of sysex data. To enable
+the optimization for sysex output, the system-dependent code
+sets fields in the pmInternal structure: fill_base, fill_offset_ptr,
+and fill_length. When fill_base is non-null, the system-independent
+part of PortMidi is allowed to directly copy sysex bytes to
+"fill_base[*fill_offset_ptr++]" until *fill_offset_ptr reaches
+fill_length. See the code for details.
+
+
+ \ No newline at end of file