aboutsummaryrefslogtreecommitdiff
path: root/portmidi/pm_win/README_WIN.txt
diff options
context:
space:
mode:
Diffstat (limited to 'portmidi/pm_win/README_WIN.txt')
-rwxr-xr-xportmidi/pm_win/README_WIN.txt174
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 @@
1File: PortMidi Win32 Readme
2Author: Belinda Thom, June 16 2002
3Revised by: Roger Dannenberg, June 2002, May 2004, June 2007,
4 Umpei Kurokawa, June 2007
5 Roger Dannenberg Sep 2009, May 2022
6
7Contents:
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=============================================================================
18USING PORTMIDI:
19=============================================================================
20
21I recommend building a static library and linking with your
22application. PortMidi is not large. See ../README.md for
23basic compiling instructions.
24
25The Windows version has a couple of extra switches: You can define
26DEBUG and MMDEBUG for a few extra messages (see the code).
27
28If PM_CHECK_ERRORS is defined, PortMidi reports and exits on any
29error. This requires terminal output to see, and aborts your
30application, so it's only intended for quick command line programs
31where you do not care to check return values and handle errors
32more robustly.
33
34PortMidi is designed to run without a console and should work perfectly
35well within a graphical user interface application.
36
37Read the portmidi.h file for PortMidi API details on using the PortMidi API.
38See <...>\pm_test\testio.c and other files in pm_test for usage examples.
39
40There are many other programs in pm_test, including a MIDI monitor.
41
42
43============================================================================
44DESIGN NOTES
45============================================================================
46
47Orderly cleanup after errors are encountered is based on a fixed order of
48steps and state changes to reflect each step. Here's the order:
49
50To 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
66SYSEX HANDLING
67
68There are three cases: simple output, stream output, input
69Each 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
80Here'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
119Here'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
143Here'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
165IMPORTANT: In addition to the above, PortMidi now has
166"shortcuts" to optimize the transfer of sysex data. To enable
167the optimization for sysex output, the system-dependent code
168sets fields in the pmInternal structure: fill_base, fill_offset_ptr,
169and fill_length. When fill_base is non-null, the system-independent
170part of PortMidi is allowed to directly copy sysex bytes to
171"fill_base[*fill_offset_ptr++]" until *fill_offset_ptr reaches
172fill_length. See the code for details.
173
174