1 /*
2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2007 Masanao Izumo <iz@onicos.co.jp>
4 Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 midi_a.c - write midi file
21
22 Author: Stas Sergeev <stsp@users.sourceforge.net>
23 Based on midi-writer code by Rober Komar <rkomar@telus.net>
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29
30 #ifdef __POCC__
31 #include <sys/types.h>
32 #endif //for off_t
33
34 #ifdef HAVE_OPEN_MEMSTREAM
35 #define _GNU_SOURCE
36 #endif
37
38 #include <stdio.h>
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif /* HAVE_UNISTD_H */
42 #ifndef NO_STRING_H
43 #include <string.h>
44 #else
45 #include <strings.h>
46 #endif
47 #ifdef HAVE_SYS_TYPES_H
48 #include <sys/types.h>
49 #endif
50 #include <fcntl.h>
51 #include <stdlib.h>
52 #include "server_defs.h"
53 #ifdef WIN32
54 #ifndef STDOUT_FILENO
55 #define STDOUT_FILENO 1
56 #endif
57 #endif
58
59 #include "timidity.h"
60 #include "common.h"
61 #include "instrum.h"
62 #include "playmidi.h"
63 #include "readmidi.h"
64 #include "output.h"
65 #include "controls.h"
66
67 #define IGNORE_TEMPO_EVENTS 0
68
69 static int open_output(void);
70 static void close_output(void);
71 static int acntl(int request, void *arg);
72
73 static char *midibuf;
74 static size_t midi_pos;
75 #ifdef HAVE_OPEN_MEMSTREAM
76 static FILE *fp;
77 #else
78 static size_t midibuf_size;
79 #define fflush(x) do {} while (0)
80 #define fclose(x) do {} while (0)
81 #endif
82
83 static long track_size_pos;
84 static double last_time;
85
86 static int tempo;
87 static int ticks_per_quarter_note;
88 #define TICKS_OFFSET 12
89
90 #define dmp midi_play_mode
91
92 PlayMode dmp = {
93 DEFAULT_RATE, 0, PF_MIDI_EVENT|PF_FILE_OUTPUT,
94 -1,
95 {0, 0, 0, 0, 0},
96 "Write MIDI file", 'm',
97 NULL,
98 open_output,
99 close_output,
100 NULL,
101 acntl
102 };
103
104 static size_t m_fwrite(const void *ptr, size_t size);
105 #define M_FWRITE_STR(s) m_fwrite(s, sizeof(s) - 1)
106 #define M_FWRITE1(a) do { \
107 uint8 __arg[1]; \
108 __arg[0] = a; \
109 m_fwrite(__arg, 1); \
110 } while (0)
111 #define M_FWRITE2(a, b) do { \
112 uint8 __arg[2]; \
113 __arg[0] = a; \
114 __arg[1] = b; \
115 m_fwrite(__arg, 2); \
116 } while (0)
117 #define M_FWRITE3(a, b, c) do { \
118 uint8 __arg[3]; \
119 __arg[0] = a; \
120 __arg[1] = b; \
121 __arg[2] = c; \
122 m_fwrite(__arg, 3); \
123 } while (0)
124
m_fwrite(const void * ptr,size_t size)125 static size_t m_fwrite(const void *ptr, size_t size)
126 {
127 #ifdef HAVE_OPEN_MEMSTREAM
128 return fwrite(ptr, size, 1, fp);
129 #else
130 if (midi_pos + size > midibuf_size) {
131 size_t new_len = (midi_pos + size) * 2;
132 midibuf = safe_realloc(midibuf, new_len);
133 midibuf_size = new_len;
134 }
135 memcpy(midibuf + midi_pos, ptr, size);
136 midi_pos += size;
137 return 1;
138 #endif
139 }
140
141 #ifndef HAVE_OPEN_MEMSTREAM
my_open_memstream(void)142 static void my_open_memstream(void)
143 {
144 midibuf_size = 1024;
145 midibuf = safe_malloc(midibuf_size);
146 midi_pos = 0;
147 }
148 #endif
149
write_midi_header(void)150 static void write_midi_header(void)
151 {
152 /* Write out MID file header.
153 * The file will have a single track, with the configured number of
154 * ticks per quarter note.
155 */
156 M_FWRITE_STR("MThd");
157 M_FWRITE_STR("\0\0\0\6"); /* header size */
158 M_FWRITE_STR("\0\0"); /* single track format */
159 M_FWRITE_STR("\0\1"); /* #tracks = 1 */
160 M_FWRITE_STR("\0\0"); /* #ticks / quarter note written later */
161 }
162
finalize_midi_header(void)163 static void finalize_midi_header(void)
164 {
165 uint16 tpqn = BE_SHORT(ticks_per_quarter_note);
166
167 fflush(fp);
168 memcpy(midibuf + TICKS_OFFSET, &tpqn, 2); /* #ticks / quarter note */
169 }
170
set_tempo(void)171 static void set_tempo(void)
172 {
173 M_FWRITE_STR("\xff\x51\3");
174 M_FWRITE3(tempo >> 16, tempo >> 8, tempo);
175 }
176
set_time_sig(void)177 static void set_time_sig(void)
178 {
179 /* Set the time sig to 4/4 */
180 M_FWRITE_STR("\xff\x58\4\4\x2\x18\x08");
181 }
182
midout_write_delta_time(int32 time)183 static void midout_write_delta_time(int32 time)
184 {
185 int32 delta_time;
186 unsigned char c[4];
187 int idx;
188 int started_printing = 0;
189
190 #if !IGNORE_TEMPO_EVENTS
191 double div;
192 delta_time = time - last_time;
193 div = (double)tempo * (double)play_mode->rate /
194 (double)(ticks_per_quarter_note * 1000000);
195 delta_time /= div;
196 last_time += delta_time * div;
197 #else
198 delta_time = time - last_time;
199 last_time += delta_time;
200 #endif
201
202 /* We have to divide the number of ticks into 7-bit segments, and only write
203 * the non-zero segments starting with the most significant (except for the
204 * least significant segment, which we always write). The most significant bit
205 * is set to 1 in all but the least significant segment.
206 */
207 c[0] = (delta_time >> 21) & 0x7f;
208 c[1] = (delta_time >> 14) & 0x7f;
209 c[2] = (delta_time >> 7) & 0x7f;
210 c[3] = (delta_time) & 0x7f;
211
212 for (idx = 0; idx < 3; idx++) {
213 if (started_printing || c[idx]) {
214 started_printing = 1;
215 M_FWRITE1(c[idx] | 0x80);
216 }
217 }
218 M_FWRITE1(c[3]);
219 }
220
start_midi_track(void)221 static void start_midi_track(void)
222 {
223 /* Write out track header.
224 * The track will have a large length (0x7fffffff) because we don't know at
225 * this time how big it will really be.
226 */
227 M_FWRITE_STR("MTrk");
228 fflush(fp);
229 track_size_pos = midi_pos;
230 M_FWRITE_STR("\x7f\xff\xff\xff"); /* #chunks */
231
232 last_time = 0;
233
234 #if !IGNORE_TEMPO_EVENTS
235 tempo = 500000;
236 #else
237 tempo = (ticks_per_quarter_note * 1000000) /
238 (double)play_mode->rate;
239 #endif
240
241 midout_write_delta_time(0);
242 set_tempo();
243 midout_write_delta_time(0);
244 set_time_sig();
245 }
246
end_midi_track(void)247 static void end_midi_track(void)
248 {
249 int32 track_bytes;
250 /* Send (with delta-time of 0) "0xff 0x2f 0x0" to finish the track. */
251 M_FWRITE_STR("\0\xff\x2f\0");
252
253 fflush(fp);
254
255 track_bytes = BE_LONG(midi_pos - track_size_pos - 4);
256 memcpy(midibuf + track_size_pos, &track_bytes, 4);
257 }
258
open_output(void)259 static int open_output(void)
260 {
261 #ifdef HAVE_OPEN_MEMSTREAM
262 fp = open_memstream(&midibuf, &midi_pos);
263 #else
264 my_open_memstream();
265 #endif
266
267 ticks_per_quarter_note = 144;
268 write_midi_header();
269
270 return 0;
271 }
272
close_output(void)273 static void close_output(void)
274 {
275 finalize_midi_header();
276
277 fclose(fp);
278 if (dmp.name) {
279 #ifndef __MACOS__
280 if (strcmp(dmp.name, "-") == 0)
281 dmp.fd = STDOUT_FILENO;
282 else
283 #endif
284 dmp.fd = open(dmp.name, FILE_OUTPUT_MODE);
285 if (dmp.fd != -1) {
286 std_write(dmp.fd, midibuf, midi_pos);
287 if (strcmp(dmp.name, "-") != 0)
288 close(dmp.fd);
289 }
290 dmp.fd = -1;
291 }
292 free(midibuf);
293 }
294
midout_noteon(int chn,int note,int vel,int32 time)295 static void midout_noteon(int chn, int note, int vel, int32 time)
296 {
297 midout_write_delta_time(time);
298 M_FWRITE3((chn & 0x0f) | MIDI_NOTEON, note & 0x7f, vel & 0x7f);
299 }
300
midout_noteoff(int chn,int note,int vel,int32 time)301 static void midout_noteoff(int chn, int note, int vel, int32 time)
302 {
303 midout_write_delta_time(time);
304 M_FWRITE3((chn & 0x0f) | MIDI_NOTEOFF, note & 0x7f, vel & 0x7f);
305 }
306
midout_control(int chn,int control,int value,int32 time)307 static void midout_control(int chn, int control, int value, int32 time)
308 {
309 midout_write_delta_time(time);
310 M_FWRITE3((chn & 0x0f) | MIDI_CTL_CHANGE, control & 0x7f, value & 0x7f);
311 }
312
midout_keypressure(int chn,int control,int value,int32 time)313 static void midout_keypressure(int chn, int control, int value, int32 time)
314 {
315 midout_write_delta_time(time);
316 M_FWRITE3((chn & 0x0f) | MIDI_KEY_PRESSURE, control & 0x7f, value & 0x7f);
317 }
318
midout_channelpressure(int chn,int vel,int32 time)319 static void midout_channelpressure(int chn, int vel, int32 time)
320 {
321 midout_write_delta_time(time);
322 M_FWRITE2((chn & 0x0f) | MIDI_CHN_PRESSURE, vel & 0x7f);
323 }
324
midout_bender(int chn,int pitch,int32 time)325 static void midout_bender(int chn, int pitch, int32 time)
326 {
327 midout_write_delta_time(time);
328 M_FWRITE3((chn & 0x0f) | MIDI_PITCH_BEND, pitch & 0x7f, (pitch >> 7) & 0x7f);
329 }
330
midout_program(int chn,int pgm,int32 time)331 static void midout_program(int chn, int pgm, int32 time)
332 {
333 midout_write_delta_time(time);
334 M_FWRITE2((chn & 0x0f) | MIDI_PGM_CHANGE, pgm & 0x7f);
335 }
336
midout_tempo(int chn,int a,int b,int32 time)337 static void midout_tempo(int chn, int a, int b, int32 time)
338 {
339 midout_write_delta_time(time);
340 tempo = (a << 16) | (b << 8) | chn;
341 set_tempo();
342 }
343
find_bit(int val)344 static int find_bit(int val)
345 {
346 int i = 0;
347 while (val) {
348 if (val & 1)
349 return i;
350 i++;
351 val >>= 1;
352 }
353 return -1;
354 }
355
midout_timesig(int chn,int a,int b,int32 time)356 static void midout_timesig(int chn, int a, int b, int32 time)
357 {
358 if (chn == 0) {
359 if (!b)
360 return;
361 b = find_bit(b);
362 midout_write_delta_time(time);
363 M_FWRITE_STR("\xff\x58\4");
364 }
365 M_FWRITE2(a, b);
366 }
367
do_event(MidiEvent * ev)368 static int do_event(MidiEvent * ev)
369 {
370 int ch, type;
371
372 ch = ev->channel;
373
374 if ((type = unconvert_midi_control_change(ev)) != -1) {
375 midout_control(ch, type, ev->a, ev->time);
376 return RC_NONE;
377 }
378
379 switch (ev->type) {
380 case ME_NOTEON:
381 midout_noteon(ch, ev->a, ev->b, ev->time);
382 break;
383 case ME_NOTEOFF:
384 midout_noteoff(ch, ev->a, ev->b, ev->time);
385 break;
386 case ME_KEYPRESSURE:
387 midout_keypressure(ch, ev->a, ev->b, ev->time);
388 break;
389 case ME_PROGRAM:
390 midout_program(ch, ev->a, ev->time);
391 break;
392 case ME_CHANNEL_PRESSURE:
393 midout_channelpressure(ch, ev->a, ev->time);
394 break;
395 case ME_PITCHWHEEL:
396 midout_bender(ch, ev->a, ev->time);
397 break;
398 case ME_TEMPO:
399 #if !IGNORE_TEMPO_EVENTS
400 midout_tempo(ch, ev->a, ev->b, ev->time);
401 #endif
402 break;
403 case ME_TIMESIG:
404 midout_timesig(ch, ev->a, ev->b, ev->time);
405 break;
406 case ME_EOT:
407 return RC_TUNE_END;
408 }
409 return RC_NONE;
410 }
411
acntl(int request,void * arg)412 static int acntl(int request, void *arg)
413 {
414 switch (request) {
415 case PM_REQ_MIDI:
416 return do_event((MidiEvent *) arg);
417 case PM_REQ_PLAY_START:
418 start_midi_track();
419 return 0;
420 case PM_REQ_PLAY_END:
421 end_midi_track();
422 return 0;
423 case PM_REQ_DIVISIONS:
424 ticks_per_quarter_note = *(int32 *) arg;
425 return 0;
426 }
427 return -1;
428 }
429