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 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 105 static void reuse_trace_node(MidiTraceList *p) 106 { 107 p->next = midi_trace.free_list; 108 midi_trace.free_list = p; 109 } 110 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 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 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 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 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 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 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 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 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 281 void trace_offset(int offset) 282 { 283 midi_trace.offset = offset; 284 } 285 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 306 void set_trace_loop_hook(void (* f)(void)) 307 { 308 midi_trace.trace_loop_hook = f; 309 } 310 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 319 void init_midi_trace(void) 320 { 321 memset(&midi_trace, 0, sizeof(midi_trace)); 322 init_mblock(&midi_trace.pool); 323 } 324 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