gzdoom-gles/src/sound/timidity++/playmidi.h
Christoph Oelckers 576932c47f - Timidity++ sources added. This compiles but isn't hooked into the engine yet.
This source has been heavily edited to remove the deep integration with the provided UI modules and to eliminate use of global variables and puts everything into a small number of C++ classes.
2018-02-19 22:14:22 +01:00

759 lines
20 KiB
C++

/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
playmidi.h
*/
#ifndef ___PLAYMIDI_H_
#define ___PLAYMIDI_H_
#include <stdint.h>
namespace TimidityPlus
{
struct AlternateAssign;
struct MidiEvent
{
int32_t time;
uint8_t type, channel, a, b;
};
#define REDUCE_CHANNELS 16
#define REVERB_MAX_DELAY_OUT (4 * playback_rate)
#define SYSEX_TAG 0xFF
/* Midi events */
enum midi_event_t
{
ME_NONE,
/* MIDI events */
ME_NOTEOFF,
ME_NOTEON,
ME_KEYPRESSURE,
ME_PROGRAM,
ME_CHANNEL_PRESSURE,
ME_PITCHWHEEL,
/* Controls */
ME_TONE_BANK_MSB,
ME_TONE_BANK_LSB,
ME_MODULATION_WHEEL,
ME_BREATH,
ME_FOOT,
ME_MAINVOLUME,
ME_BALANCE,
ME_PAN,
ME_EXPRESSION,
ME_SUSTAIN,
ME_PORTAMENTO_TIME_MSB,
ME_PORTAMENTO_TIME_LSB,
ME_PORTAMENTO,
ME_PORTAMENTO_CONTROL,
ME_DATA_ENTRY_MSB,
ME_DATA_ENTRY_LSB,
ME_SOSTENUTO,
ME_SOFT_PEDAL,
ME_LEGATO_FOOTSWITCH,
ME_HOLD2,
ME_HARMONIC_CONTENT,
ME_RELEASE_TIME,
ME_ATTACK_TIME,
ME_BRIGHTNESS,
ME_REVERB_EFFECT,
ME_TREMOLO_EFFECT,
ME_CHORUS_EFFECT,
ME_CELESTE_EFFECT,
ME_PHASER_EFFECT,
ME_RPN_INC,
ME_RPN_DEC,
ME_NRPN_LSB,
ME_NRPN_MSB,
ME_RPN_LSB,
ME_RPN_MSB,
ME_ALL_SOUNDS_OFF,
ME_RESET_CONTROLLERS,
ME_ALL_NOTES_OFF,
ME_MONO,
ME_POLY,
/* TiMidity Extensionals */
ME_MASTER_TUNING, /* Master tuning */
ME_SCALE_TUNING, /* Scale tuning */
ME_BULK_TUNING_DUMP, /* Bulk tuning dump */
ME_SINGLE_NOTE_TUNING, /* Single-note tuning */
ME_RANDOM_PAN,
ME_SET_PATCH, /* Install special instrument */
ME_DRUMPART,
ME_KEYSHIFT,
ME_PATCH_OFFS, /* Change special instrument sample position
* Channel, LSB, MSB
*/
/* Global channel events */
ME_TEMPO,
ME_CHORUS_TEXT,
ME_LYRIC,
ME_GSLCD, /* GS L.C.D. Exclusive message event */
ME_MARKER,
ME_INSERT_TEXT, /* for SC */
ME_TEXT,
ME_KARAOKE_LYRIC, /* for KAR format */
ME_MASTER_VOLUME,
ME_RESET, /* Reset and change system mode */
ME_NOTE_STEP,
ME_TIMESIG, /* Time signature */
ME_KEYSIG, /* Key signature */
ME_TEMPER_KEYSIG, /* Temperament key signature */
ME_TEMPER_TYPE, /* Temperament type */
ME_MASTER_TEMPER_TYPE, /* Master temperament type */
ME_USER_TEMPER_ENTRY, /* User-defined temperament entry */
ME_SYSEX_LSB, /* Universal system exclusive message (LSB) */
ME_SYSEX_MSB, /* Universal system exclusive message (MSB) */
ME_SYSEX_GS_LSB, /* GS system exclusive message (LSB) */
ME_SYSEX_GS_MSB, /* GS system exclusive message (MSB) */
ME_SYSEX_XG_LSB, /* XG system exclusive message (LSB) */
ME_SYSEX_XG_MSB, /* XG system exclusive message (MSB) */
ME_WRD, /* for MIMPI WRD tracer */
ME_SHERRY, /* for Sherry WRD tracer */
ME_BARMARKER,
ME_STEP, /* for Metronome */
ME_LAST = 254, /* Last sequence of MIDI list.
* This event is reserved for realtime player.
*/
ME_EOT = 255 /* End of MIDI. Finish to play */
};
#define GLOBAL_CHANNEL_EVENT_TYPE(type) \
((type) == ME_NONE || (type) >= ME_TEMPO)
enum rpn_data_address_t /* NRPN/RPN */
{
NRPN_ADDR_0108,
NRPN_ADDR_0109,
NRPN_ADDR_010A,
NRPN_ADDR_0120,
NRPN_ADDR_0121,
NRPN_ADDR_0130,
NRPN_ADDR_0131,
NRPN_ADDR_0134,
NRPN_ADDR_0135,
NRPN_ADDR_0163,
NRPN_ADDR_0164,
NRPN_ADDR_0166,
NRPN_ADDR_1400,
NRPN_ADDR_1500,
NRPN_ADDR_1600,
NRPN_ADDR_1700,
NRPN_ADDR_1800,
NRPN_ADDR_1900,
NRPN_ADDR_1A00,
NRPN_ADDR_1C00,
NRPN_ADDR_1D00,
NRPN_ADDR_1E00,
NRPN_ADDR_1F00,
NRPN_ADDR_3000,
NRPN_ADDR_3100,
NRPN_ADDR_3400,
NRPN_ADDR_3500,
RPN_ADDR_0000,
RPN_ADDR_0001,
RPN_ADDR_0002,
RPN_ADDR_0003,
RPN_ADDR_0004,
RPN_ADDR_0005,
RPN_ADDR_7F7F,
RPN_ADDR_FFFF,
RPN_MAX_DATA_ADDR
};
#define RX_PITCH_BEND (1<<0)
#define RX_CH_PRESSURE (1<<1)
#define RX_PROGRAM_CHANGE (1<<2)
#define RX_CONTROL_CHANGE (1<<3)
#define RX_POLY_PRESSURE (1<<4)
#define RX_NOTE_MESSAGE (1<<5)
#define RX_RPN (1<<6)
#define RX_NRPN (1<<7)
#define RX_MODULATION (1<<8)
#define RX_VOLUME (1<<9)
#define RX_PANPOT (1<<10)
#define RX_EXPRESSION (1<<11)
#define RX_HOLD1 (1<<12)
#define RX_PORTAMENTO (1<<13)
#define RX_SOSTENUTO (1<<14)
#define RX_SOFT (1<<15)
#define RX_NOTE_ON (1<<16)
#define RX_NOTE_OFF (1<<17)
#define RX_BANK_SELECT (1<<18)
#define RX_BANK_SELECT_LSB (1<<19)
enum {
EG_ATTACK = 0,
EG_DECAY = 2,
EG_DECAY1 = 1,
EG_DECAY2 = 2,
EG_RELEASE = 3,
EG_NULL = 5,
EG_GUS_ATTACK = 0,
EG_GUS_DECAY = 1,
EG_GUS_SUSTAIN = 2,
EG_GUS_RELEASE1 = 3,
EG_GUS_RELEASE2 = 4,
EG_GUS_RELEASE3 = 5,
EG_SF_ATTACK = 0,
EG_SF_HOLD = 1,
EG_SF_DECAY = 2,
EG_SF_RELEASE = 3,
};
#ifndef PART_EQ_XG
#define PART_EQ_XG
/*! shelving filter */
struct filter_shelving
{
double freq, gain, q;
int32_t x1l, x2l, y1l, y2l, x1r, x2r, y1r, y2r;
int32_t a1, a2, b0, b1, b2;
};
/*! Part EQ (XG) */
struct part_eq_xg {
int8_t bass, treble, bass_freq, treble_freq;
filter_shelving basss, trebles;
int8_t valid;
};
#endif /* PART_EQ_XG */
struct midi_controller
{
int16_t val;
int8_t pitch; /* in +-semitones [-24, 24] */
int16_t cutoff; /* in +-cents [-9600, 9600] */
float amp; /* [-1.0, 1.0] */
/* in GS, LFO1 means LFO for voice 1, LFO2 means LFO for voice2.
LFO2 is not supported. */
float lfo1_rate, lfo2_rate; /* in +-Hz [-10.0, 10.0] */
int16_t lfo1_pitch_depth, lfo2_pitch_depth; /* in cents [0, 600] */
int16_t lfo1_tvf_depth, lfo2_tvf_depth; /* in cents [0, 2400] */
float lfo1_tva_depth, lfo2_tva_depth; /* [0, 1.0] */
int8_t variation_control_depth, insertion_control_depth;
};
struct DrumPartEffect
{
int32_t *buf;
int8_t note, reverb_send, chorus_send, delay_send;
};
struct DrumParts
{
int8_t drum_panning;
int32_t drum_envelope_rate[6]; /* drum instrument envelope */
int8_t pan_random; /* flag for drum random pan */
float drum_level;
int8_t chorus_level, reverb_level, delay_level, coarse, fine,
play_note, drum_cutoff_freq, drum_resonance;
int32_t rx;
};
struct Channel
{
int8_t bank_msb, bank_lsb, bank, program, volume,
expression, sustain, panning, mono, portamento,
key_shift, loop_timeout;
/* chorus, reverb... Coming soon to a 300-MHz, eight-way superscalar
processor near you */
int8_t chorus_level, /* Chorus level */
reverb_level; /* Reverb level. */
int reverb_id; /* Reverb ID used for reverb optimize implementation
>=0 reverb_level
-1: DEFAULT_REVERB_SEND_LEVEL
*/
int8_t delay_level; /* Delay Send Level */
int8_t eq_gs; /* EQ ON/OFF (GS) */
int8_t insertion_effect;
/* Special sample ID. (0 means Normal sample) */
uint8_t special_sample;
int pitchbend;
double
pitchfactor; /* precomputed pitch bend factor to save some fdiv's */
/* For portamento */
uint8_t portamento_time_msb, portamento_time_lsb;
int porta_control_ratio, porta_dpb;
int32_t last_note_fine;
/* For Drum part */
struct DrumParts *drums[128];
/* For NRPN Vibrato */
int32_t vibrato_depth, vibrato_delay;
float vibrato_ratio;
/* For RPN */
uint8_t rpnmap[RPN_MAX_DATA_ADDR]; /* pseudo RPN address map */
uint8_t rpnmap_lsb[RPN_MAX_DATA_ADDR];
uint8_t lastlrpn, lastmrpn;
int8_t nrpn; /* 0:RPN, 1:NRPN, -1:Undefined */
int rpn_7f7f_flag; /* Boolean flag used for RPN 7F/7F */
/* For channel envelope */
int32_t envelope_rate[6]; /* for Envelope Generator in mix.c
* 0: value for attack rate
* 2: value for decay rate
* 3: value for release rate
*/
int mapID; /* Program map ID */
AlternateAssign *altassign; /* Alternate assign patch table */
int32_t lasttime; /* Last sample time of computed voice on this channel */
/* flag for random pan */
int pan_random;
/* for Voice LPF / Resonance */
int8_t param_resonance, param_cutoff_freq; /* -64 ~ 63 */
float cutoff_freq_coef, resonance_dB;
int8_t velocity_sense_depth, velocity_sense_offset;
int8_t scale_tuning[12], prev_scale_tuning;
int8_t temper_type;
int8_t soft_pedal;
int8_t sostenuto;
int8_t damper_mode;
int8_t tone_map0_number;
double pitch_offset_fine; /* in Hz */
int8_t assign_mode;
int8_t legato; /* legato footswitch */
int8_t legato_flag; /* note-on flag for legato */
midi_controller mod, bend, caf, paf, cc1, cc2;
ChannelBitMask channel_layer;
int port_select;
struct part_eq_xg eq_xg;
int8_t dry_level;
int8_t note_limit_high, note_limit_low; /* Note Limit (Keyboard Range) */
int8_t vel_limit_high, vel_limit_low; /* Velocity Limit */
int32_t rx; /* Rx. ~ (Rcv ~) */
int drum_effect_num;
int8_t drum_effect_flag;
struct DrumPartEffect *drum_effect;
int8_t sysex_gs_msb_addr, sysex_gs_msb_val,
sysex_xg_msb_addr, sysex_xg_msb_val, sysex_msb_addr, sysex_msb_val;
};
/* Causes the instrument's default panning to be used. */
#define NO_PANNING -1
typedef struct {
int16_t freq, last_freq, orig_freq;
double reso_dB, last_reso_dB, orig_reso_dB, reso_lin;
int8_t type; /* filter type. 0: Off, 1: 12dB/oct, 2: 24dB/oct */
int32_t f, q, p; /* coefficients in fixed-point */
int32_t b0, b1, b2, b3, b4;
float gain;
int8_t start_flag;
} FilterCoefficients;
#define ENABLE_PAN_DELAY
#define PAN_DELAY_BUF_MAX 48 /* 0.5ms in 96kHz */
typedef struct {
uint8_t
status, channel, note, velocity;
int vid, temper_instant;
Sample *sample;
int64_t sample_offset; /* sample_offset must be signed */
int32_t
orig_frequency, frequency, sample_increment,
envelope_volume, envelope_target, envelope_increment,
tremolo_sweep, tremolo_sweep_position,
tremolo_phase, tremolo_phase_increment,
vibrato_sweep, vibrato_sweep_position;
final_volume_t left_mix, right_mix;
int32_t old_left_mix, old_right_mix,
left_mix_offset, right_mix_offset,
left_mix_inc, right_mix_inc;
double
left_amp, right_amp, tremolo_volume;
int32_t
vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS], vibrato_delay;
int
vibrato_phase, orig_vibrato_control_ratio, vibrato_control_ratio,
vibrato_depth, vibrato_control_counter,
envelope_stage, control_counter, panning, panned;
int16_t tremolo_depth;
/* for portamento */
int porta_control_ratio, porta_control_counter, porta_dpb;
int32_t porta_pb;
int delay; /* Note ON delay samples */
int32_t timeout;
struct cache_hash *cache;
uint8_t chorus_link; /* Chorus link */
int8_t proximate_flag;
FilterCoefficients fc;
double envelope_scale, last_envelope_volume;
int32_t inv_envelope_scale;
int modenv_stage;
int32_t
modenv_volume, modenv_target, modenv_increment;
double last_modenv_volume;
int32_t tremolo_delay, modenv_delay;
int32_t delay_counter;
#ifdef ENABLE_PAN_DELAY
int32_t *pan_delay_buf, pan_delay_rpt, pan_delay_wpt, pan_delay_spt;
#endif /* ENABLE_PAN_DELAY */
} Voice;
/* Voice status options: */
#define VOICE_FREE (1<<0)
#define VOICE_ON (1<<1)
#define VOICE_SUSTAINED (1<<2)
#define VOICE_OFF (1<<3)
#define VOICE_DIE (1<<4)
/* Voice panned options: */
#define PANNED_MYSTERY 0
#define PANNED_LEFT 1
#define PANNED_RIGHT 2
#define PANNED_CENTER 3
/* Anything but PANNED_MYSTERY only uses the left volume */
enum {
MODULE_TIMIDITY_DEFAULT = 0x0,
/* GS modules */
MODULE_SC55 = 0x1,
MODULE_SC88 = 0x2,
MODULE_SC88PRO = 0x3,
MODULE_SC8850 = 0x4,
/* XG modules */
MODULE_MU50 = 0x10,
MODULE_MU80 = 0x11,
MODULE_MU90 = 0x12,
MODULE_MU100 = 0x13,
/* GM modules */
MODULE_SBLIVE = 0x20,
MODULE_SBAUDIGY = 0x21,
/* Special modules */
MODULE_TIMIDITY_SPECIAL1 = 0x70,
MODULE_TIMIDITY_DEBUG = 0x7f,
};
struct midi_file_info
{
int readflag;
char *seq_name;
char *karaoke_title;
char *first_text;
int16_t hdrsiz;
int16_t format;
int16_t tracks;
int32_t divisions;
int time_sig_n, time_sig_d, time_sig_c, time_sig_b; /* Time signature */
int drumchannels_isset;
ChannelBitMask drumchannels;
ChannelBitMask drumchannel_mask;
int32_t samples;
int max_channel;
int compressed; /* True if midi_data is compressed */
};
class Recache;
class Mixer;
class Reverb;
class AudioQueue;
class Player
{
public:
Channel channel[MAX_CHANNELS];
Voice voice[max_voices];
ChannelBitMask default_drumchannel_mask;
ChannelBitMask default_drumchannels;
ChannelBitMask drumchannel_mask;
ChannelBitMask drumchannels;
double *vol_table;
private:
Recache *recache;
Mixer *mixer;
Reverb *reverb;
AudioQueue *aq;
MidiEvent *current_event;
int32_t sample_count; /* Length of event_list */
int32_t current_sample; /* Number of calclated samples */
double midi_time_ratio; /* For speed up/down */
int note_key_offset = 0; /* For key up/down */
ChannelBitMask channel_mute; /* For channel mute */
double master_volume;
int32_t master_volume_ratio;
int play_system_mode;
int midi_streaming;
int volatile stream_max_compute; /* compute time limit (in msec) when streaming */
int8_t current_keysig;
int8_t current_temper_keysig;
int temper_adj;
int32_t current_play_tempo;
int opt_realtime_playing;
int check_eot_flag;
int playmidi_seek_flag;
int opt_pure_intonation;
int current_freq_table;
int current_temper_freq_table;
int master_tuning;
int make_rvid_flag; /* For reverb optimization */
int32_t amplification;
int voices, upper_voices;
struct midi_file_info midifileinfo, *current_file_info;
MBlockList playmidi_pool;
int32_t freq_table_user[4][48][128];
char *reverb_buffer; /* MAX_CHANNELS*AUDIO_BUFFER_SIZE*8 */
int32_t lost_notes, cut_notes;
int32_t common_buffer[AUDIO_BUFFER_SIZE * 2], *buffer_pointer; /* stereo samples */
int16_t wav_buffer[AUDIO_BUFFER_SIZE * 2];
int32_t buffered_count;
int32_t insertion_effect_buffer[AUDIO_BUFFER_SIZE * 2];
/* Ring voice id for each notes. This ID enables duplicated note. */
uint8_t vidq_head[128 * MAX_CHANNELS], vidq_tail[128 * MAX_CHANNELS];
int MIDI_EVENT_NOTE(MidiEvent *ep)
{
return (ISDRUMCHANNEL((ep)->channel) ? (ep)->a : (((int)(ep)->a + note_key_offset + channel[ep->channel].key_shift) & 0x7f));
}
int32_t MIDI_EVENT_TIME(MidiEvent *ep)
{
return ((int32_t)((ep)->time * midi_time_ratio + 0.5));
}
int16_t conv_lfo_pitch_depth(float val)
{
return (int16_t)(0.0318f * val * val + 0.6858f * val + 0.5f);
}
int16_t conv_lfo_filter_depth(float val)
{
return (int16_t)((0.0318f * val * val + 0.6858f * val) * 4.0f + 0.5f);
}
bool IS_SYSEX_EVENT_TYPE(MidiEvent *event);
double cnv_Hz_to_vib_ratio(double freq);
int new_vidq(int ch, int note);
int last_vidq(int ch, int note);
void reset_voices(void);
void kill_note(int i);
void kill_all_voices(void);
void reset_drum_controllers(struct DrumParts *d[], int note);
void reset_nrpn_controllers(int c);
void reset_controllers(int c);
int32_t calc_velocity(int32_t ch, int32_t vel);
void recompute_voice_tremolo(int v);
void recompute_amp(int v);
void reset_midi(int playing);
void recompute_channel_filter(int ch, int note);
void init_voice_filter(int i);
int reduce_voice(void);
int find_free_voice(void);
int get_panning(int ch, int note, int v);
void init_voice_vibrato(int v);
void init_voice_pan_delay(int v);
void init_voice_portamento(int v);
void init_voice_tremolo(int v);
void start_note(MidiEvent *e, int i, int vid, int cnt);
void set_envelope_time(int ch, int val, int stage);
void new_chorus_voice_alternate(int v1, int level);
void note_on(MidiEvent *e);
void update_sostenuto_controls(int ch);
void update_redamper_controls(int ch);
void note_off(MidiEvent *e);
void all_notes_off(int c);
void all_sounds_off(int c);
void adjust_pressure(MidiEvent *e);
void adjust_channel_pressure(MidiEvent *e);
void adjust_panning(int c);
void adjust_drum_panning(int ch, int note);
void drop_sustain(int c);
void adjust_all_pitch(void);
void adjust_pitch(int c);
void adjust_volume(int c);
void set_reverb_level(int ch, int level);
void make_drum_effect(int ch);
void adjust_master_volume(void);
void add_channel_layer(int to_ch, int from_ch);
void remove_channel_layer(int ch);
void process_sysex_event(int ev, int ch, int val, int b);
double gs_cnv_vib_rate(int rate);
int32_t gs_cnv_vib_depth(int depth);
int32_t gs_cnv_vib_delay(int delay);
int last_rpn_addr(int ch);
void voice_increment(int n);
void voice_decrement(int n);
void voice_decrement_conservative(int n);
void mix_signal(int32_t *dest, int32_t *src, int32_t count);
int is_insertion_effect_xg(int ch);
void do_compute_data(int32_t count);
int check_midi_play_end(MidiEvent *e, int len);
int midi_play_end(void);
int compute_data(int32_t count);
void update_modulation_wheel(int ch);
void drop_portamento(int ch);
void update_portamento_time(int ch);
void update_legato_controls(int ch);
void set_master_tuning(int tune);
struct midi_file_info *new_midi_file_info();
void adjust_amplification(void);
void init_freq_table_user(void);
int find_samples(MidiEvent *, int *);
int select_play_sample(Sample *, int, int *, int *, MidiEvent *);
double get_play_note_ratio(int, int);
int find_voice(MidiEvent *);
void finish_note(int i);
void update_portamento_controls(int ch);
void update_rpn_map(int ch, int addr, int update_now);
void set_single_note_tuning(int, int, int, int);
void set_user_temper_entry(int, int, int);
void recompute_bank_parameter(int, int);
float calc_drum_tva_level(int ch, int note, int level);
int32_t calc_random_delay(int ch, int note);
/* XG Part EQ */
void init_part_eq_xg(struct part_eq_xg *);
void recompute_part_eq_xg(struct part_eq_xg *);
/* MIDI controllers (MW, Bend, CAf, PAf,...) */
void init_midi_controller(midi_controller *);
float get_midi_controller_amp(midi_controller *);
float get_midi_controller_filter_cutoff(midi_controller *);
float get_midi_controller_filter_depth(midi_controller *);
int32_t get_midi_controller_pitch(midi_controller *);
int16_t get_midi_controller_pitch_depth(midi_controller *);
int16_t get_midi_controller_amp_depth(midi_controller *);
/* Rx. ~ (Rcv ~) */
void init_rx(int);
void set_rx(int, int32_t, int);
void init_rx_drum(struct DrumParts *);
void set_rx_drum(struct DrumParts *, int32_t, int);
int32_t get_rx_drum(struct DrumParts *, int32_t);
public:
Player();
~Player();
bool ISDRUMCHANNEL(int c)
{
return !!IS_SET_CHANNELMASK(drumchannels, c);
}
int midi_drumpart_change(int ch, int isdrum);
int get_reverb_level(int ch);
int get_chorus_level(int ch);
Instrument *play_midi_load_instrument(int dr, int bk, int prog);
void midi_program_change(int ch, int prog);
void free_voice(int v);
void play_midi_setup_drums(int ch, int note);
/* For stream player */
void playmidi_stream_init(void);
void playmidi_tmr_reset(void);
int play_event(MidiEvent *ev);
void recompute_voice_filter(int);
void free_drum_effect(int);
void change_system_mode(int mode);
struct midi_file_info *get_midi_file_info(const char *filename, int newp);
void recompute_freq(int v);
int get_default_mapID(int ch);
void init_channel_layer(int ch);
// Only until streaming works.
void skip_to(int32_t until_time, MidiEvent *evt_start);
int play_midi(MidiEvent *eventlist, int32_t samples);
friend MidiEvent *groom_list(int32_t divisions, int32_t *eventsp, int32_t *samplesp);
};
class SysexConvert
{
const int midi_port_number = 0;
uint8_t rhythm_part[2] = { 0,0 }; /* for GS */
uint8_t drum_setup_xg[16] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; /* for XG */
public:
int parse_sysex_event_multi(uint8_t *val, int32_t len, MidiEvent *evm, Instruments *instruments);
int parse_sysex_event(uint8_t *val, int32_t len, MidiEvent *ev, Instruments *instruments);
};
// really extern!
int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret);
}
#endif /* ___PLAYMIDI_H_ */