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