1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.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 
21     miditrace.c - Midi audio synchronized tracer
22     Written by Masanao Izumo <mo@goice.co.jp>
23 */
24 
25 
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #ifdef __POCC__
30 #include <sys/types.h>
31 #endif //for off_t
32 #include <stdio.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif /* HAVE_UNISTD_H */
36 #include <stdlib.h>
37 
38 #ifndef NO_STRING_H
39 #include <string.h>
40 #else
41 #include <strings.h>
42 #endif
43 
44 #include "timidity.h"
45 #include "common.h"
46 #include "instrum.h"
47 #include "playmidi.h"
48 #include "output.h"
49 #include "controls.h"
50 #include "miditrace.h"
51 #include "wrd.h"
52 #include "aq.h"
53 
54 enum trace_argtypes
55 {
56     ARG_VOID,
57     ARG_INT,
58     ARG_INT_INT,
59     ARG_CE,
60     ARGTIME_VP,
61 };
62 
63 typedef struct _MidiTraceList
64 {
65     int32 start;	/* Samples to start */
66     int argtype;	/* Argument type */
67 
68     union { /* Argument */
69 	int args[2];
70 	uint16 ui16;
71 	CtlEvent ce;
72 	void *v;
73     } a;
74 
75     union { /* Handler function */
76 	void (*f0)(void);
77 	void (*f1)(int);
78 	void (*f2)(int, int);
79 	void (*fce)(CtlEvent *ce);
80 	void (*fv)(void *);
81     } f;
82 
83     struct _MidiTraceList *next; /* Chain link next node */
84 } MidiTraceList;
85 
86 
87 MidiTrace midi_trace;
88 extern int32 current_sample;
89 
new_trace_node(void)90 static MidiTraceList *new_trace_node(void)
91 {
92     MidiTraceList *p;
93 
94     if(midi_trace.free_list == NULL)
95 	p = (MidiTraceList *)new_segment(&midi_trace.pool,
96 					 sizeof(MidiTraceList));
97     else
98     {
99 	p = midi_trace.free_list;
100 	midi_trace.free_list = midi_trace.free_list->next;
101     }
102     return p;
103 }
104 
reuse_trace_node(MidiTraceList * p)105 static void reuse_trace_node(MidiTraceList *p)
106 {
107     p->next = midi_trace.free_list;
108     midi_trace.free_list = p;
109 }
110 
trace_start_time(void)111 static int32 trace_start_time(void)
112 {
113     if(play_mode->flag & PF_CAN_TRACE)
114 	return current_sample;
115     return -1;
116 }
117 
run_midi_trace(MidiTraceList * p)118 static void run_midi_trace(MidiTraceList *p)
119 {
120     if(!ctl->opened)
121 	return;
122 
123     switch(p->argtype)
124     {
125       case ARG_VOID:
126 	p->f.f0();
127 	break;
128       case ARG_INT:
129 	p->f.f1(p->a.args[0]);
130 	break;
131       case ARG_INT_INT:
132 	p->f.f2(p->a.args[0], p->a.args[1]);
133 	break;
134       case ARGTIME_VP:
135 	p->f.fv(p->a.v);
136 	break;
137       case ARG_CE:
138 	p->f.fce(&p->a.ce);
139 	break;
140     }
141 }
142 
midi_trace_setfunc(MidiTraceList * node)143 static MidiTraceList *midi_trace_setfunc(MidiTraceList *node)
144 {
145     MidiTraceList *p;
146 
147     if(!ctl->trace_playing || node->start < 0)
148     {
149 	run_midi_trace(node);
150 	return NULL;
151     }
152 
153     p = new_trace_node();
154     *p = *node;
155     p->next = NULL;
156 
157     if(midi_trace.head == NULL)
158 	midi_trace.head = midi_trace.tail = p;
159     else
160     {
161 	midi_trace.tail->next = p;
162 	midi_trace.tail = p;
163     }
164 
165     return p;
166 }
167 
push_midi_trace0(void (* f)(void))168 void push_midi_trace0(void (*f)(void))
169 {
170     MidiTraceList node;
171     if(f == NULL)
172 	return;
173     memset(&node, 0, sizeof(node));
174     node.start = trace_start_time();
175     node.argtype = ARG_VOID;
176     node.f.f0 = f;
177     midi_trace_setfunc(&node);
178 }
179 
push_midi_trace1(void (* f)(int),int arg1)180 void push_midi_trace1(void (*f)(int), int arg1)
181 {
182     MidiTraceList node;
183     if(f == NULL)
184 	return;
185     memset(&node, 0, sizeof(node));
186     node.start = trace_start_time();
187     node.argtype = ARG_INT;
188     node.f.f1 = f;
189     node.a.args[0] = arg1;
190     midi_trace_setfunc(&node);
191 }
192 
push_midi_trace2(void (* f)(int,int),int arg1,int arg2)193 void push_midi_trace2(void (*f)(int, int), int arg1, int arg2)
194 {
195     MidiTraceList node;
196     if(f == NULL)
197 	return;
198     memset(&node, 0, sizeof(node));
199     node.start = trace_start_time();
200     node.argtype = ARG_INT_INT;
201     node.f.f2 = f;
202     node.a.args[0] = arg1;
203     node.a.args[1] = arg2;
204     midi_trace_setfunc(&node);
205 }
206 
push_midi_trace_ce(void (* f)(CtlEvent *),CtlEvent * ce)207 void push_midi_trace_ce(void (*f)(CtlEvent *), CtlEvent *ce)
208 {
209     MidiTraceList node;
210     if(f == NULL)
211 	return;
212     memset(&node, 0, sizeof(node));
213     node.start = trace_start_time();
214     node.argtype = ARG_CE;
215     node.f.fce = f;
216     node.a.ce = *ce;
217     midi_trace_setfunc(&node);
218 }
219 
push_midi_time_vp(int32 start,void (* f)(void *),void * vp)220 void push_midi_time_vp(int32 start, void (*f)(void *), void *vp)
221 {
222     MidiTraceList node;
223     if(f == NULL)
224 	return;
225     memset(&node, 0, sizeof(node));
226     node.start = start;
227     node.argtype = ARGTIME_VP;
228     node.f.fv = f;
229     node.a.v = vp;
230     midi_trace_setfunc(&node);
231 }
232 
trace_loop(void)233 int32 trace_loop(void)
234 {
235     int32 cur;
236     int ctl_update;
237     static int lasttime = -1;
238 
239     if(midi_trace.trace_loop_hook != NULL)
240 	midi_trace.trace_loop_hook();
241 
242     if(midi_trace.head == NULL)
243 	return 0;
244 
245     if((cur = current_trace_samples()) == -1 || !ctl->trace_playing)
246 	cur = 0x7fffffff; /* apply all trace event */
247 
248     ctl_update = 0;
249     while(midi_trace.head && cur >= midi_trace.head->start
250 	  && cur > 0) /* privent flying start */
251     {
252 	MidiTraceList *p;
253 
254 	p = midi_trace.head;
255 	run_midi_trace(p);
256 	if(p->argtype == ARG_CE)
257 	    ctl_update = 1;
258 	midi_trace.head = midi_trace.head->next;
259 	reuse_trace_node(p);
260     }
261 
262     if(ctl_update)
263 	ctl_mode_event(CTLE_REFRESH, 0, 0, 0);
264 
265     if(midi_trace.head == NULL)
266     {
267 	midi_trace.tail = NULL;
268 	return 0; /* No more tracing */
269     }
270 
271     if(!ctl_update)
272     {
273 	if(lasttime == cur)
274 	    midi_trace.head->start--;	/* avoid infinite loop */
275 	lasttime = cur;
276     }
277 
278     return 1; /* must call trace_loop() continued */
279 }
280 
trace_offset(int offset)281 void trace_offset(int offset)
282 {
283     midi_trace.offset = offset;
284 }
285 
trace_flush(void)286 void trace_flush(void)
287 {
288     midi_trace.flush_flag = 1;
289     wrd_midi_event(WRD_START_SKIP, WRD_NOARG);
290     while(midi_trace.head)
291     {
292 	MidiTraceList *p;
293 
294 	p = midi_trace.head;
295 	run_midi_trace(p);
296 	midi_trace.head = midi_trace.head->next;
297 	reuse_trace_node(p);
298     }
299     wrd_midi_event(WRD_END_SKIP, WRD_NOARG);
300     reuse_mblock(&midi_trace.pool);
301     midi_trace.head = midi_trace.tail = midi_trace.free_list = NULL;
302     ctl_mode_event(CTLE_REFRESH, 0, 0, 0);
303     midi_trace.flush_flag = 0;
304 }
305 
set_trace_loop_hook(void (* f)(void))306 void set_trace_loop_hook(void (* f)(void))
307 {
308     midi_trace.trace_loop_hook = f;
309 }
310 
current_trace_samples(void)311 int32 current_trace_samples(void)
312 {
313     int32 sp;
314     if((sp = aq_samples()) == -1)
315 	return -1;
316     return midi_trace.offset + aq_samples();
317 }
318 
init_midi_trace(void)319 void init_midi_trace(void)
320 {
321     memset(&midi_trace, 0, sizeof(midi_trace));
322     init_mblock(&midi_trace.pool);
323 }
324 
trace_wait_samples(void)325 int32 trace_wait_samples(void)
326 {
327     int32 s;
328 
329     if(midi_trace.head == NULL)
330 	return -1;
331     if((s = current_trace_samples()) == -1)
332 	return 0;
333     s = midi_trace.head->start - s;
334     if(s < 0)
335 	s = 0;
336     return s;
337 }
338