diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-07 06:50:04 +0200 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-07 06:50:04 +0200 |
| commit | 988f5d2b5343850e19ad1512cefe6c53953aa02e (patch) | |
| tree | 1ff29934294e73b2575488c06df91866ce251dbe /portmidi/pm_win/README_WIN.txt | |
| parent | 9b5839c58a2e1df8bddf6b98805998508ea417d5 (diff) | |
| download | ttdaw-988f5d2b5343850e19ad1512cefe6c53953aa02e.tar.gz | |
Added bunch of examples
Diffstat (limited to 'portmidi/pm_win/README_WIN.txt')
| -rwxr-xr-x | portmidi/pm_win/README_WIN.txt | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/portmidi/pm_win/README_WIN.txt b/portmidi/pm_win/README_WIN.txt new file mode 100755 index 0000000..8bfb467 --- /dev/null +++ b/portmidi/pm_win/README_WIN.txt | |||
| @@ -0,0 +1,174 @@ | |||
| 1 | File: PortMidi Win32 Readme | ||
| 2 | Author: Belinda Thom, June 16 2002 | ||
| 3 | Revised by: Roger Dannenberg, June 2002, May 2004, June 2007, | ||
| 4 | Umpei Kurokawa, June 2007 | ||
| 5 | Roger Dannenberg Sep 2009, May 2022 | ||
| 6 | |||
| 7 | Contents: | ||
| 8 | Using Portmidi | ||
| 9 | To Install Portmidi | ||
| 10 | To Compile Portmidi | ||
| 11 | About Cmake | ||
| 12 | Using other versions of Visual C++ | ||
| 13 | To Create Your Own Portmidi Client Application | ||
| 14 | |||
| 15 | |||
| 16 | |||
| 17 | ============================================================================= | ||
| 18 | USING PORTMIDI: | ||
| 19 | ============================================================================= | ||
| 20 | |||
| 21 | I recommend building a static library and linking with your | ||
| 22 | application. PortMidi is not large. See ../README.md for | ||
| 23 | basic compiling instructions. | ||
| 24 | |||
| 25 | The Windows version has a couple of extra switches: You can define | ||
| 26 | DEBUG and MMDEBUG for a few extra messages (see the code). | ||
| 27 | |||
| 28 | If PM_CHECK_ERRORS is defined, PortMidi reports and exits on any | ||
| 29 | error. This requires terminal output to see, and aborts your | ||
| 30 | application, so it's only intended for quick command line programs | ||
| 31 | where you do not care to check return values and handle errors | ||
| 32 | more robustly. | ||
| 33 | |||
| 34 | PortMidi is designed to run without a console and should work perfectly | ||
| 35 | well within a graphical user interface application. | ||
| 36 | |||
| 37 | Read the portmidi.h file for PortMidi API details on using the PortMidi API. | ||
| 38 | See <...>\pm_test\testio.c and other files in pm_test for usage examples. | ||
| 39 | |||
| 40 | There are many other programs in pm_test, including a MIDI monitor. | ||
| 41 | |||
| 42 | |||
| 43 | ============================================================================ | ||
| 44 | DESIGN NOTES | ||
| 45 | ============================================================================ | ||
| 46 | |||
| 47 | Orderly cleanup after errors are encountered is based on a fixed order of | ||
| 48 | steps and state changes to reflect each step. Here's the order: | ||
| 49 | |||
| 50 | To open input: | ||
| 51 | initialize return value to NULL | ||
| 52 | - allocate the PmInternal strucure (representation of PortMidiStream) | ||
| 53 | return value is (non-null) PmInternal structure | ||
| 54 | - allocate midi buffer | ||
| 55 | set buffer field of PmInternal structure | ||
| 56 | - call system-dependent open code | ||
| 57 | - allocate midiwinmm_type for winmm dependent data | ||
| 58 | set descriptor field of PmInternal structure | ||
| 59 | - open device | ||
| 60 | set handle field of midiwinmm_type structure | ||
| 61 | - allocate buffers | ||
| 62 | - start device | ||
| 63 | - return | ||
| 64 | - return | ||
| 65 | |||
| 66 | SYSEX HANDLING | ||
| 67 | |||
| 68 | There are three cases: simple output, stream output, input | ||
| 69 | Each must deal with: | ||
| 70 | 1. Buffer Initialization (creating buffers) | ||
| 71 | 2. Buffer Allocation (finding a free buffer) | ||
| 72 | 3. Buffer Fill (putting bytes in the buffer) | ||
| 73 | 4. Buffer Preparation (midiOutPrepare, etc.) | ||
| 74 | 5. Buffer Send (to Midi device) | ||
| 75 | 6. Buffer Receive (in callback) | ||
| 76 | 7. Buffer Empty (removing bytes from buffer) | ||
| 77 | 8. Buffer Free (returning to the buffer pool) | ||
| 78 | 9. Buffer Finalization (returning to heap) | ||
| 79 | |||
| 80 | Here's how simple output handles sysex: | ||
| 81 | 1. Buffer Initialization (creating buffers) | ||
| 82 | allocated when code tries to write first byte to a buffer | ||
| 83 | the test is "if (!m->sysex_buffers[0]) { ... }" | ||
| 84 | this field is initialized to NULL when device is opened | ||
| 85 | the size is SYSEX_BYTES_PER_BUFFER | ||
| 86 | allocate_sysex_buffers() does the initialization | ||
| 87 | note that the actual size of the allocation includes | ||
| 88 | additional space for a MIDIEVENT (3 longs) which are | ||
| 89 | not used in this case | ||
| 90 | 2. Buffer Allocation (finding a free buffer) | ||
| 91 | see get_free_sysex_buffer() | ||
| 92 | cycle through m->sysex_buffers[] using m->next_sysex_buffer | ||
| 93 | to determine where to look next | ||
| 94 | if nothing is found, wait by blocking on m->sysex_buffer_signal | ||
| 95 | this is signaled by the callback every time a message is | ||
| 96 | received | ||
| 97 | 3. Buffer Fill (putting bytes in the buffer) | ||
| 98 | essentially a state machine approach | ||
| 99 | hdr->dwBytesRecorded is a position in message pointed to by m->hdr | ||
| 100 | keep appending bytes until dwBytesRecorded >= SYSEX_BYTES_PER_BUFFER | ||
| 101 | then send the message, reseting the state to initial values | ||
| 102 | 4. Buffer Preparation (midiOutPrepare, etc.) | ||
| 103 | just before sending in winmm_end_sysex() | ||
| 104 | 5. Buffer Send (to Midi device) | ||
| 105 | message is padded with zero at end (since extra space was allocated | ||
| 106 | this is ok) -- the zero works around a bug in (an old version of) | ||
| 107 | MIDI YOKE drivers | ||
| 108 | dwBufferLength gets dwBytesRecorded, and dwBytesRecorded gets 0 | ||
| 109 | uses midiOutLongMsg() | ||
| 110 | 6. Buffer Receive (in callback) | ||
| 111 | 7. Buffer Empty (removing bytes from buffer) | ||
| 112 | not applicable for output | ||
| 113 | 8. Buffer Free (returning to the buffer pool) | ||
| 114 | unprepare message to indicate that it is free | ||
| 115 | SetEvent on m->buffer_signal in case client is waiting | ||
| 116 | 9. Buffer Finalization (returning to heap) | ||
| 117 | when device is closed, winmm_out_delete frees all sysex buffers | ||
| 118 | |||
| 119 | Here's how stream output handles sysex: | ||
| 120 | 1. Buffer Initialization (creating buffers) | ||
| 121 | same code as simple output (see above) | ||
| 122 | 2. Buffer Allocation (finding a free buffer) | ||
| 123 | same code as simple output (see above) | ||
| 124 | 3. Buffer Fill (putting bytes in the buffer) | ||
| 125 | essentially a state machine approach | ||
| 126 | m->dwBytesRecorded is a position in message | ||
| 127 | keep appending bytes until buffer is full (one byte to spare) | ||
| 128 | 4. Buffer Preparation (midiOutPrepare, etc.) | ||
| 129 | done before sending message | ||
| 130 | dwBytesRecorded and dwBufferLength are set in winmm_end_sysex | ||
| 131 | 5. Buffer Send (to Midi device) | ||
| 132 | uses midiStreamOutMsg() | ||
| 133 | 6. Buffer Receive (in callback) | ||
| 134 | 7. Buffer Empty (removing bytes from buffer) | ||
| 135 | not applicable for output | ||
| 136 | 8. Buffer Free (returning to the buffer pool) | ||
| 137 | unprepare message to indicate that it is free | ||
| 138 | SetEvent on m->buffer_signal in case client is waiting | ||
| 139 | 9. Buffer Finalization (returning to heap) | ||
| 140 | when device is closed, winmm_out_delete frees all sysex buffers | ||
| 141 | |||
| 142 | |||
| 143 | Here's how input handles sysex: | ||
| 144 | 1. Buffer Initialization (creating buffers) | ||
| 145 | two buffers are allocated in winmm_in_open | ||
| 146 | 2. Buffer Allocation (finding a free buffer) | ||
| 147 | same code as simple output (see above) | ||
| 148 | 3. Buffer Fill (putting bytes in the buffer) | ||
| 149 | not applicable for input | ||
| 150 | 4. Buffer Preparation (midiOutPrepare, etc.) | ||
| 151 | done before sending message -- in winmm_in_open and in callback | ||
| 152 | 5. Buffer Send (to Midi device) | ||
| 153 | uses midiInAddbuffer in allocate_sysex_input_buffer (called from | ||
| 154 | winmm_in_open) and callback | ||
| 155 | 6. Buffer Receive (in callback) | ||
| 156 | 7. Buffer Empty (removing bytes from buffer) | ||
| 157 | done without pause in loop in callback | ||
| 158 | 8. Buffer Free (returning to the buffer pool) | ||
| 159 | done by midiInAddBuffer in callback, no pointer to buffers | ||
| 160 | is retained except by device | ||
| 161 | 9. Buffer Finalization (returning to heap) | ||
| 162 | when device is closed, empty buffers are delivered to callback, | ||
| 163 | which frees them | ||
| 164 | |||
| 165 | IMPORTANT: In addition to the above, PortMidi now has | ||
| 166 | "shortcuts" to optimize the transfer of sysex data. To enable | ||
| 167 | the optimization for sysex output, the system-dependent code | ||
| 168 | sets fields in the pmInternal structure: fill_base, fill_offset_ptr, | ||
| 169 | and fill_length. When fill_base is non-null, the system-independent | ||
| 170 | part of PortMidi is allowed to directly copy sysex bytes to | ||
| 171 | "fill_base[*fill_offset_ptr++]" until *fill_offset_ptr reaches | ||
| 172 | fill_length. See the code for details. | ||
| 173 | |||
| 174 | |||
