/* FluidSynth - A Software Synthesizer * * Copyright (C) 2003 Peter Hanappe and others. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307, USA */ #ifndef _FLUID_MIDI_H #define _FLUID_MIDI_H #include "fluidsynth_priv.h" #include "fluid_sys.h" #include "fluid_list.h" typedef struct _fluid_midi_parser_t fluid_midi_parser_t; fluid_midi_parser_t* new_fluid_midi_parser(void); int delete_fluid_midi_parser(fluid_midi_parser_t* parser); fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigned char c); int fluid_midi_send_event(fluid_synth_t* synth, fluid_player_t* player, fluid_midi_event_t* evt); /*************************************************************** * * CONSTANTS & ENUM */ #define MAX_NUMBER_OF_TRACKS 128 enum fluid_midi_event_type { /* channel messages */ NOTE_OFF = 0x80, NOTE_ON = 0x90, KEY_PRESSURE = 0xa0, CONTROL_CHANGE = 0xb0, PROGRAM_CHANGE = 0xc0, CHANNEL_PRESSURE = 0xd0, PITCH_BEND = 0xe0, /* system exclusive */ MIDI_SYSEX = 0xf0, /* system common - never in midi files */ MIDI_TIME_CODE = 0xf1, MIDI_SONG_POSITION = 0xf2, MIDI_SONG_SELECT = 0xf3, MIDI_TUNE_REQUEST = 0xf6, MIDI_EOX = 0xf7, /* system real-time - never in midi files */ MIDI_SYNC = 0xf8, MIDI_TICK = 0xf9, MIDI_START = 0xfa, MIDI_CONTINUE = 0xfb, MIDI_STOP = 0xfc, MIDI_ACTIVE_SENSING = 0xfe, MIDI_SYSTEM_RESET = 0xff, /* meta event - for midi files only */ MIDI_META_EVENT = 0xff }; enum fluid_midi_control_change { BANK_SELECT_MSB = 0x00, MODULATION_MSB = 0x01, BREATH_MSB = 0x02, FOOT_MSB = 0x04, PORTAMENTO_TIME_MSB = 0x05, DATA_ENTRY_MSB = 0x06, VOLUME_MSB = 0x07, BALANCE_MSB = 0x08, PAN_MSB = 0x0A, EXPRESSION_MSB = 0x0B, EFFECTS1_MSB = 0x0C, EFFECTS2_MSB = 0x0D, GPC1_MSB = 0x10, /* general purpose controller */ GPC2_MSB = 0x11, GPC3_MSB = 0x12, GPC4_MSB = 0x13, BANK_SELECT_LSB = 0x20, MODULATION_WHEEL_LSB = 0x21, BREATH_LSB = 0x22, FOOT_LSB = 0x24, PORTAMENTO_TIME_LSB = 0x25, DATA_ENTRY_LSB = 0x26, VOLUME_LSB = 0x27, BALANCE_LSB = 0x28, PAN_LSB = 0x2A, EXPRESSION_LSB = 0x2B, EFFECTS1_LSB = 0x2C, EFFECTS2_LSB = 0x2D, GPC1_LSB = 0x30, GPC2_LSB = 0x31, GPC3_LSB = 0x32, GPC4_LSB = 0x33, SUSTAIN_SWITCH = 0x40, PORTAMENTO_SWITCH = 0x41, SOSTENUTO_SWITCH = 0x42, SOFT_PEDAL_SWITCH = 0x43, LEGATO_SWITCH = 0x45, HOLD2_SWITCH = 0x45, SOUND_CTRL1 = 0x46, SOUND_CTRL2 = 0x47, SOUND_CTRL3 = 0x48, SOUND_CTRL4 = 0x49, SOUND_CTRL5 = 0x4A, SOUND_CTRL6 = 0x4B, SOUND_CTRL7 = 0x4C, SOUND_CTRL8 = 0x4D, SOUND_CTRL9 = 0x4E, SOUND_CTRL10 = 0x4F, GPC5 = 0x50, GPC6 = 0x51, GPC7 = 0x52, GPC8 = 0x53, PORTAMENTO_CTRL = 0x54, EFFECTS_DEPTH1 = 0x5B, EFFECTS_DEPTH2 = 0x5C, EFFECTS_DEPTH3 = 0x5D, EFFECTS_DEPTH4 = 0x5E, EFFECTS_DEPTH5 = 0x5F, DATA_ENTRY_INCR = 0x60, DATA_ENTRY_DECR = 0x61, NRPN_LSB = 0x62, NRPN_MSB = 0x63, RPN_LSB = 0x64, RPN_MSB = 0x65, ALL_SOUND_OFF = 0x78, ALL_CTRL_OFF = 0x79, LOCAL_CONTROL = 0x7A, ALL_NOTES_OFF = 0x7B, OMNI_OFF = 0x7C, OMNI_ON = 0x7D, POLY_OFF = 0x7E, POLY_ON = 0x7F }; /* General MIDI RPN event numbers (LSB, MSB = 0) */ enum midi_rpn_event { RPN_PITCH_BEND_RANGE = 0x00, RPN_CHANNEL_FINE_TUNE = 0x01, RPN_CHANNEL_COARSE_TUNE = 0x02, RPN_TUNING_PROGRAM_CHANGE = 0x03, RPN_TUNING_BANK_SELECT = 0x04, RPN_MODULATION_DEPTH_RANGE = 0x05 }; enum midi_meta_event { MIDI_COPYRIGHT = 0x02, MIDI_TRACK_NAME = 0x03, MIDI_INST_NAME = 0x04, MIDI_LYRIC = 0x05, MIDI_MARKER = 0x06, MIDI_CUE_POINT = 0x07, MIDI_EOT = 0x2f, MIDI_SET_TEMPO = 0x51, MIDI_SMPTE_OFFSET = 0x54, MIDI_TIME_SIGNATURE = 0x58, MIDI_KEY_SIGNATURE = 0x59, MIDI_SEQUENCER_EVENT = 0x7f }; enum fluid_player_status { FLUID_PLAYER_READY, FLUID_PLAYER_PLAYING, FLUID_PLAYER_DONE }; enum fluid_driver_status { FLUID_MIDI_READY, FLUID_MIDI_LISTENING, FLUID_MIDI_DONE }; /*************************************************************** * * TYPE DEFINITIONS & FUNCTION DECLARATIONS */ /* From ctype.h */ #define fluid_isascii(c) (((c) & ~0x7f) == 0) /* * fluid_midi_event_t */ struct _fluid_midi_event_t { fluid_midi_event_t* next; /* Don't use it, it will dissappear. Used in midi tracks. */ unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */ unsigned char type; /* MIDI event type */ unsigned char channel; /* MIDI channel */ unsigned int param1; /* First parameter */ unsigned int param2; /* Second parameter */ }; /* * fluid_track_t */ struct _fluid_track_t { char* name; int num; fluid_midi_event_t *first; fluid_midi_event_t *cur; fluid_midi_event_t *last; unsigned int ticks; }; typedef struct _fluid_track_t fluid_track_t; fluid_track_t* new_fluid_track(int num); int delete_fluid_track(fluid_track_t* track); int fluid_track_set_name(fluid_track_t* track, char* name); char* fluid_track_get_name(fluid_track_t* track); int fluid_track_add_event(fluid_track_t* track, fluid_midi_event_t* evt); fluid_midi_event_t* fluid_track_first_event(fluid_track_t* track); fluid_midi_event_t* fluid_track_next_event(fluid_track_t* track); int fluid_track_get_duration(fluid_track_t* track); int fluid_track_reset(fluid_track_t* track); int fluid_track_send_events(fluid_track_t* track, fluid_synth_t* synth, fluid_player_t* player, unsigned int ticks); #define fluid_track_eot(track) ((track)->cur == NULL) /* * fluid_player */ struct _fluid_player_t { int status; int loop; int ntracks; fluid_track_t *track[MAX_NUMBER_OF_TRACKS]; fluid_synth_t* synth; fluid_timer_t* timer; fluid_list_t* playlist; char* current_file; char send_program_change; /* should we ignore the program changes? */ int start_ticks; /* the number of tempo ticks passed at the last tempo change */ int cur_ticks; /* the number of tempo ticks passed */ int begin_msec; /* the time (msec) of the beginning of the file */ int start_msec; /* the start time of the last tempo change */ int cur_msec; /* the current time */ int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec per midi-clock. bravo! */ double deltatime; /* milliseconds per midi tick. depends on set-tempo */ unsigned int division; }; int fluid_player_add_track(fluid_player_t* player, fluid_track_t* track); int fluid_player_callback(void* data, unsigned int msec); int fluid_player_count_tracks(fluid_player_t* player); fluid_track_t* fluid_player_get_track(fluid_player_t* player, int i); int fluid_player_reset(fluid_player_t* player); int fluid_player_load(fluid_player_t* player, char *filename); /* * fluid_midi_file */ typedef struct { fluid_file fp; int running_status; int c; int type; int ntracks; int uses_smpte; unsigned int smpte_fps; unsigned int smpte_res; unsigned int division; /* If uses_SMPTE == 0 then division is ticks per beat (quarter-note) */ double tempo; /* Beats per second (SI rules =) */ int tracklen; int trackpos; int eot; int varlen; int dtime; } fluid_midi_file; fluid_midi_file* new_fluid_midi_file(char* filename); void delete_fluid_midi_file(fluid_midi_file* mf); int fluid_midi_file_read_mthd(fluid_midi_file* midifile); int fluid_midi_file_load_tracks(fluid_midi_file* midifile, fluid_player_t* player); int fluid_midi_file_read_track(fluid_midi_file* mf, fluid_player_t* player, int num); int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track); int fluid_midi_file_read_varlen(fluid_midi_file* mf); int fluid_midi_file_getc(fluid_midi_file* mf); int fluid_midi_file_push(fluid_midi_file* mf, int c); int fluid_midi_file_read(fluid_midi_file* mf, void* buf, int len); int fluid_midi_file_skip(fluid_midi_file* mf, int len); int fluid_midi_file_read_tracklen(fluid_midi_file* mf); int fluid_midi_file_eot(fluid_midi_file* mf); int fluid_midi_file_get_division(fluid_midi_file* midifile); int fluid_midi_event_length(unsigned char status); /* How many parameters may a MIDI event have? */ #define FLUID_MIDI_PARSER_MAX_PAR 3 /* * fluid_midi_parser_t */ struct _fluid_midi_parser_t { unsigned char status; /* Identifies the type of event, that is currently received ('Noteon', 'Pitch Bend' etc). */ unsigned char channel; /* The channel of the event that is received (in case of a channel event) */ unsigned int nr_bytes; /* How many bytes have been read for the current event? */ unsigned int nr_bytes_total; /* How many bytes does the current event type include? */ unsigned short p[FLUID_MIDI_PARSER_MAX_PAR]; /* The parameters */ fluid_midi_event_t event; /* The event, that is returned to the MIDI driver. */ }; int fluid_isasciistring(char* s); long fluid_getlength(unsigned char *s); int fluid_midi_router_send_event(fluid_midi_router_t* router, fluid_midi_event_t* event); #endif /* _FLUID_MIDI_H */