source: ext/midi/midi_player.c @ 5b1fff7

feature/autosinkfeature/cnnfeature/cnn_orgfeature/constantqfeature/crepefeature/crepe_orgfeature/pitchshiftfeature/pydocstringsfeature/timestretchfix/ffmpeg5pitchshiftsamplertimestretchyinfft+
Last change on this file since 5b1fff7 was 1789b0c, checked in by Paul Brossier <piem@piem.org>, 15 years ago

ext/midi/midi_player.c: use AUBIO_LSMP_FMT

  • Property mode set to 100644
File size: 13.9 KB
Line 
1/*
2 * Copyright (C) 2003  Peter Hanappe and others.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License
6 * as published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 * 
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 * 02111-1307, USA
18 */
19
20/* this file originally taken from FluidSynth - A Software Synthesizer
21 * modified by Paul Brossier for aubio
22 */
23
24/**
25 *
26 * \bug timer still broken
27 *      (should use alsa seq anyway) (fixed?) realtime playing is slower than
28 *      it should. moved msec_passed and deltatime to microseconds (usec)
29 *      (rounding were causing the drift) the new offline version is not quite
30 *      exact yet.
31 *
32 * \bug the player does not seem to understand a ``reprise'' in a file
33 */
34
35#include "aubio_priv.h"
36#include "list.h"
37#include "timer.h"
38#include "midi.h"
39#include "midi_event.h"
40#include "midi_track.h"
41#include "midi_player.h"
42#include "midi_file.h"
43
44
45/** aubio_midi_player */
46struct _aubio_midi_player_t {
47  aubio_track_t  *track[AUBIO_MIDI_PLAYER_MAX_TRACKS];
48  aubio_timer_t* timer;
49  sint_t         status;
50  sint_t         loop;
51  sint_t         ntracks;
52  aubio_list_t*  playlist;
53  char*          current_file;
54  char           send_program_change;/**< should we ignore the program changes? */
55  sint_t         ticks_passed;       /**< number of midi ticks that have passed */
56  sint_t         usec_passed;        /**< number of microseconds that have passed */
57  sint_t         miditempo;          /**< as indicated by midi settempo: n 24th of a
58  *                                     usec per midi-clock. bravo! */
59  lsmp_t         deltatime;          /**< microseconds per midi tick. depends on
60  *                                     set-tempo */
61  uint_t         division;           /**< the number of ticks per beat (quarter-note)
62  *                                     in the file*/
63  //aubio_synth_t*                        synth;
64};
65
66/******************************************************
67 *
68 *     aubio_midi_player
69 */
70/** new_aubio_midi_player */
71aubio_midi_player_t* new_aubio_midi_player()
72  //aubio_midi_player_t* new_aubio_midi_player(aubio_synth_t* synth)
73{
74  sint_t i;
75  aubio_midi_player_t* player;
76  player = AUBIO_NEW(aubio_midi_player_t);
77  if (player == NULL) {
78    AUBIO_ERR( "Out of memory");
79    return NULL;
80  }
81  player->status  = AUBIO_MIDI_PLAYER_READY;
82  player->loop    = 0;
83  player->ntracks = 0;
84  for (i = 0; i < AUBIO_MIDI_PLAYER_MAX_TRACKS; i++) {
85    player->track[i] = NULL;
86  }
87  //player->synth = synth;
88  player->timer               = NULL;
89  player->playlist            = NULL;
90  player->current_file        = NULL;
91  player->division            = 0;
92  player->send_program_change = 1;
93  player->ticks_passed        = 0;
94  player->usec_passed         = 0;
95  player->miditempo           = 480000;
96  player->deltatime           = 4000.0;
97  return player;
98}
99
100/** delete_aubio_midi_player */
101sint_t del_aubio_midi_player(aubio_midi_player_t* player)
102{
103  if (player == NULL) {
104    return AUBIO_OK;
105  }
106  aubio_midi_player_stop(player);
107  aubio_midi_player_reset(player);
108  AUBIO_FREE(player);
109  return AUBIO_OK;
110}
111
112/** aubio_midi_player_reset */
113sint_t aubio_midi_player_reset(aubio_midi_player_t* player)
114{
115  sint_t i;
116
117  for (i = 0; i < AUBIO_MIDI_PLAYER_MAX_TRACKS; i++) {
118    if (player->track[i] != NULL) {
119      del_aubio_track(player->track[i]);
120      player->track[i] = NULL;
121    }
122  }
123  player->current_file        = NULL;
124  player->status              = AUBIO_MIDI_PLAYER_READY;
125  player->loop                = 0;
126  player->ntracks             = 0;
127  player->division            = 0;
128  player->send_program_change = 1;
129  player->ticks_passed        = 0;
130  player->usec_passed         = 0;
131  player->miditempo           = 480000;
132  player->deltatime           = 4000.0;
133  return 0;
134}
135
136/** aubio_midi_player_add_track */
137sint_t aubio_midi_player_add_track(aubio_midi_player_t* player, aubio_track_t* track)
138{
139  if (player->ntracks < AUBIO_MIDI_PLAYER_MAX_TRACKS) {
140    player->track[player->ntracks++] = track;
141    return AUBIO_OK;
142  } else {
143    return AUBIO_FAIL;
144  }
145}
146
147/** aubio_midi_player_count_tracks */
148sint_t aubio_midi_player_count_tracks(aubio_midi_player_t* player)
149{
150  return player->ntracks;
151}
152
153/** aubio_midi_player_get_track */
154aubio_track_t* aubio_midi_player_get_track(aubio_midi_player_t* player, sint_t i)
155{
156  if ((i >= 0) && (i < AUBIO_MIDI_PLAYER_MAX_TRACKS)) {
157    return player->track[i];
158  } else {
159    return NULL;
160  }
161}
162
163/** aubio_midi_player_get_track */
164sint_t aubio_midi_player_add(aubio_midi_player_t* player, char* midifile)
165{
166  char *s = AUBIO_STRDUP(midifile);
167  player->playlist = aubio_list_append(player->playlist, s);
168  return 0;
169}
170
171/** aubio_midi_player_load */
172sint_t aubio_midi_player_load(aubio_midi_player_t* player, char *filename)
173{
174  aubio_midi_file_t* midifile;
175
176  midifile = new_aubio_midi_file(filename); 
177  if (midifile == NULL) {
178    return AUBIO_FAIL;
179  }
180  player->division = aubio_midi_file_get_division(midifile);
181
182  AUBIO_DBG("quarter note division=%d\n", player->division); 
183
184  if (aubio_midi_file_load_tracks(midifile, player) != AUBIO_OK){
185    return AUBIO_FAIL;
186  }
187
188  AUBIO_DBG("Tracks loaded\n"); 
189
190  del_aubio_midi_file(midifile);
191  return AUBIO_OK; 
192}
193
194/** aubio_midi_player_callback */
195sint_t aubio_midi_player_callback(void* data, uint_t usec)
196{
197  sint_t i;
198  uint_t ticks;
199  uint_t delta_ticks;
200  sint_t status = AUBIO_MIDI_PLAYER_DONE;
201  aubio_midi_player_t* player;
202  //aubio_synth_t* synth;
203  player  = (aubio_midi_player_t*) data;
204  //synth = player->synth;
205
206  /* Load the next file if necessary */
207  while (player->current_file == NULL) {
208
209    if (player->playlist == NULL) {
210      return 0;
211    }
212
213    aubio_midi_player_reset(player);
214
215    player->current_file = aubio_list_get(player->playlist);
216    player->playlist = aubio_list_next(player->playlist);
217
218    //AUBIO_DBG( "%s: %d: Loading midifile %s", __FILE__, __LINE__, player->current_file);
219    AUBIO_DBG("Loading midifile %s\n", player->current_file);
220
221    if (aubio_midi_player_load(player, player->current_file) == AUBIO_OK) {
222
223      player->ticks_passed = 0;
224      player->usec_passed = 0;
225
226      for (i = 0; i < player->ntracks; i++) {
227        if (player->track[i] != NULL) {
228          aubio_track_reset(player->track[i]);
229        }
230      }
231
232    } else {
233      player->current_file = NULL;
234    }
235  }
236
237  delta_ticks = (uint_t) ((lsmp_t)(usec - player->usec_passed) / player->deltatime);
238  ticks = player->ticks_passed + delta_ticks;
239
240  for (i = 0; i < player->ntracks; i++) {
241    if (!aubio_track_eot(player->track[i])) {
242      status = AUBIO_MIDI_PLAYER_PLAYING;
243      if (aubio_track_send_events(player->track[i], /*synth,*/ player, ticks) != AUBIO_OK) {
244        /* */
245      }
246    }
247  }
248
249  player->status       = status;
250  player->ticks_passed = ticks;
251  player->usec_passed  = usec;
252
253  if (player->status == AUBIO_MIDI_PLAYER_DONE) {
254    player->current_file = NULL; 
255  }
256
257  return 1;
258}
259
260/** aubio_midi_player_play */
261sint_t aubio_midi_player_play(aubio_midi_player_t* player)
262{
263  AUBIO_DBG("Starting midi player\n");
264  if (player->status == AUBIO_MIDI_PLAYER_PLAYING) {
265    AUBIO_DBG("Midi player already playing\n");
266    return AUBIO_OK;
267  }
268
269  if (player->playlist == NULL) {
270    AUBIO_DBG("No playlist\n");
271    return AUBIO_FAIL;
272  }
273
274  player->status = AUBIO_MIDI_PLAYER_PLAYING;
275
276  /** \bug timer is still in millisec, should be moved to microseconds,
277   *     and replaced in favor of the alsa sequencer api */
278  player->timer = new_aubio_timer((sint_t) player->deltatime * 1.e-3, aubio_midi_player_callback, 
279      (void*) player, 1, 0);
280  if (player->timer == NULL) {
281    AUBIO_DBG("Failed creating timer for midi player.\n");
282    return AUBIO_FAIL;
283  }
284  if (player->current_file == NULL) {
285      AUBIO_DBG("No more file.\n");
286      delete_aubio_timer(player->timer);
287      return AUBIO_FAIL;
288  }
289
290  return AUBIO_OK;
291}
292
293/** aubio_midi_player_play_offline */
294sint_t aubio_midi_player_play_offline(aubio_midi_player_t* player)
295{
296  uint_t usec = 0; /* start looking n ms in advance */
297  AUBIO_DBG("Starting midi player\n");
298  if (player->status == AUBIO_MIDI_PLAYER_PLAYING) {
299    AUBIO_DBG("Midi player already playing\n");
300    return AUBIO_OK;
301  }
302
303  if (player->playlist == NULL) {
304    AUBIO_DBG("No playlist\n");
305    return AUBIO_FAIL;
306  }
307
308  //AUBIO_DBG("Starting callback.\n");
309  player->status = AUBIO_MIDI_PLAYER_PLAYING;
310
311  /* no timer, no thread ! */
312  while(aubio_midi_player_callback((void *)player,usec))
313  { 
314    /* step at least one microsecond forward */
315    usec += 1 + player->deltatime;
316    if (player->status == AUBIO_MIDI_PLAYER_DONE)
317      break;
318  }
319  //AUBIO_DBG("End of callback.\n");
320 
321  if (player->current_file == NULL) {
322      AUBIO_DBG("No more file.\n");
323      return AUBIO_FAIL;
324  }
325  return AUBIO_OK;
326}
327/** aubio_midi_player_stop */
328sint_t aubio_midi_player_stop(aubio_midi_player_t* player)
329{
330  if (player->timer != NULL) {
331    delete_aubio_timer(player->timer);
332  }
333  player->status = AUBIO_MIDI_PLAYER_DONE;
334  player->timer = NULL;
335  return AUBIO_OK;
336}
337
338/** aubio_midi_player_set_loop */
339sint_t aubio_midi_player_set_loop(aubio_midi_player_t* player, sint_t loop)
340{
341  player->loop = loop;
342  return AUBIO_OK;
343}
344
345/**  aubio_midi_player_set_midi_tempo */
346sint_t aubio_midi_player_set_midi_tempo(aubio_midi_player_t* player, sint_t tempo)
347{
348  player->miditempo = tempo;
349  //player->deltatime = (lsmp_t) tempo / player->division * 1.e-3; /* in milliseconds */
350  player->deltatime = (lsmp_t) tempo / player->division; /* in microseconds */
351
352  AUBIO_DBG("Tempo Change: %d tempo=%f tick time=" AUBIO_LSMP_FMT " msec\n",
353  //    player->usec_passed, 60.*1.e6/tempo, player->deltatime);
354      player->usec_passed, 60.*1.e6/tempo, 1.e-3*player->deltatime);
355 
356  return AUBIO_OK;
357}
358
359/** aubio_midi_player_set_bpm */
360sint_t aubio_midi_player_set_bpm(aubio_midi_player_t* player, sint_t bpm)
361{
362  return aubio_midi_player_set_midi_tempo(player, (sint_t)((lsmp_t) 60 * 1e6 / bpm));
363}
364
365/** aubio_midi_player_join */
366sint_t aubio_midi_player_join(aubio_midi_player_t* player)
367{
368  return player->timer? aubio_timer_join(player->timer) : AUBIO_OK;
369}
370
371/** aubio_track_send_events */
372sint_t aubio_track_send_events(aubio_track_t* track, 
373    //    aubio_synth_t* synth,
374    aubio_midi_player_t* player,
375    uint_t ticks)
376{
377  sint_t status = AUBIO_OK;
378  aubio_midi_event_t* event;
379
380  while (1) {
381
382    event = track->cur;
383    if (event == NULL) {
384      return status;
385    }
386    /* prsint_t each midi tick */
387    /*
388       AUBIO_DBG("track=%d\tticks=%u\ttrack=%u\tdtime=%u\tnext=%u\n",
389       track->num,
390       ticks,
391       track->ticks,
392       event->dtime,
393       track->ticks + event->dtime);
394       */
395
396    if (track->ticks + event->dtime > ticks) {
397      return status;
398    }
399
400    track->ticks += event->dtime;
401    status = aubio_midi_send_event(/*synth, */player, event);
402    aubio_track_next_event(track);
403
404  }
405  return status;
406}
407
408
409/**
410 * aubio_midi_send_event
411 *
412 * This is a utility function that doesn't really belong to any class or
413 * structure. It is called by aubio_midi_track and aubio_midi_device.
414 *
415 * \note This could be moved to a callback function defined in the main programs
416 */
417//sint_t aubio_midi_send_event(aubio_synth_t* synth, aubio_player_t* player, aubio_midi_event_t* event)
418sint_t aubio_midi_send_event(aubio_midi_player_t* player, aubio_midi_event_t* event)
419{
420  /* current time in seconds */
421  //smpl_t print_time = player->msec_passed * 1e-3;
422  smpl_t print_time = player->usec_passed * 1e-6;
423  switch (event->type) {
424    case NOTE_ON:
425      AUBIO_MSG("Time=%f, chan=%d, pitch=%d vol=%d \n", 
426          print_time, event->channel, event->param1, event->param2);
427      /*if (aubio_synth_noteon(synth, event->channel, event->param1, event->param2) != AUBIO_OK) {
428        return AUBIO_FAIL;
429      }*/
430      break;
431    case NOTE_OFF:
432      AUBIO_MSG("Time=%f, chan=%d, pitch=%d, vol=0\n",
433          print_time, event->channel, event->param1);
434      /*if (aubio_synth_noteoff(synth, event->channel, event->param1) != AUBIO_OK) {
435        return AUBIO_FAIL;
436      }*/
437      break;
438    case CONTROL_CHANGE:
439      AUBIO_MSG("Time=%f Parameter, chan=%d c1=%d c2=%d\n",
440          print_time, event->channel, event->param1, event->param2);
441      /*if (aubio_synth_cc(synth, event->channel, event->param1, event->param2) != AUBIO_OK) {
442        return AUBIO_FAIL;
443      }*/
444      break;
445    case MIDI_SET_TEMPO:
446      if (player != NULL) {
447        if (aubio_midi_player_set_midi_tempo(player, event->param1) != AUBIO_OK) {
448          return AUBIO_FAIL;
449        }
450      }
451      break;
452    case PROGRAM_CHANGE:
453      AUBIO_MSG("Time=%f Program, chan=%d program=%d\n",
454          print_time, event->channel, event->param1);
455      /*if (aubio_synth_program_change(synth, event->channel, event->param1) != AUBIO_OK) {
456        return AUBIO_FAIL;
457      }*/
458      break;
459    case PITCH_BEND:
460      AUBIO_MSG("Time=%f Pitchbend, chan=%d msb=%d lsb=%d \n", 
461          print_time, event->channel, event->param1, event->param2);
462      /*if (aubio_synth_pitch_bend(synth, event->channel, event->param1) != AUBIO_OK) {
463        return AUBIO_FAIL;
464      }
465      break;*/
466    default:
467      break;
468  }
469  return AUBIO_OK;
470}
471
472
473/**
474 * aubio_midi_receive_event
475 *
476 * \note This could be moved to a callback function defined in the main programs
477 */
478sint_t aubio_midi_receive_event(aubio_midi_player_t* player UNUSED, aubio_midi_event_t* event)
479{
480  /* current time in seconds */
481  //smpl_t print_time = player->msec_passed * 1e-3;
482  //smpl_t print_time = player->usec_passed * 1e-6;
483  switch (event->type) {
484    case NOTE_ON:
485      break;
486    case NOTE_OFF:
487      break;
488    default:
489      break;
490  }
491  return AUBIO_OK;
492}
Note: See TracBrowser for help on using the repository browser.