📄 playmidi.c
字号:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <stdlib.h>
#ifndef NO_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <math.h>
#ifdef __W32__
#include <windows.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include "timidity.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "readmidi.h"
#include "output.h"
#include "mix.h"
#include "controls.h"
#include "miditrace.h"
#include "recache.h"
#include "arc.h"
#include "reverb.h"
#include "wrd.h"
#include "aq.h"
#include "freq.h"
#define ABORT_AT_FATAL 1 /*#################*/
#define MYCHECK(s) do { if(s == 0) { printf("## L %d\n", __LINE__); abort(); } } while(0)
extern VOLATILE int intr;
#ifdef SOLARIS
/* shut gcc warning up */
int usleep(unsigned int useconds);
#endif
#ifdef SUPPORT_SOUNDSPEC
#include "soundspec.h"
#endif /* SUPPORT_SOUNDSPEC */
#include "tables.h"
#define PLAY_INTERLEAVE_SEC 1.0
#define PORTAMENTO_TIME_TUNING (1.0 / 5000.0)
#define PORTAMENTO_CONTROL_RATIO 256 /* controls per sec */
/*#define DEFAULT_CHORUS_DELAY1 0.02
#define DEFAULT_CHORUS_DELAY2 0.003*/
double DEFAULT_CHORUS_DELAY1 = 0.02;
double DEFAULT_CHORUS_DELAY2 = 0.003;
#define CHORUS_OPPOSITE_THRESHOLD 32
/*#define CHORUS_VELOCITY_TUNING1 0.7
#define CHORUS_VELOCITY_TUNING2 0.6*/
double CHORUS_VELOCITY_TUNING1 = 0.7;
double CHORUS_VELOCITY_TUNING2 = 0.6;
int CHORUS_VELOCITY_DELTA = 16; /* sms debug 046.05 change new_chorus_voice*() */
#define EOT_PRESEARCH_LEN 32
#define SPEED_CHANGE_RATE 1.0594630943592953 /* 2^(1/12) */
/* Undefine if you don't want to use auto voice reduce implementation */
#define REDUCE_VOICE_TIME_TUNING (play_mode->rate/5) /* 0.2 sec */
#ifdef REDUCE_VOICE_TIME_TUNING
static int max_good_nv = 1;
static int min_bad_nv = 256;
static int32 ok_nv_total = 32;
static int32 ok_nv_counts = 1;
static int32 ok_nv_sample = 0;
static int ok_nv = 32;
static int old_rate = -1;
#endif
static int prescanning_flag;
static int32 midi_restart_time = 0;
Channel channel[MAX_CHANNELS];
Voice voice[MAX_VOICES];
int32 current_play_tempo = 500000;
int opt_realtime_playing = 0;
int reduce_voice_threshold = -1;
static MBlockList playmidi_pool;
int check_eot_flag;
int special_tonebank = -1;
int default_tonebank = 0;
int playmidi_seek_flag = 0;
int play_pause_flag = 0;
static int file_from_stdin;
static void set_reverb_level(int ch, int level);
static int make_rvid_flag = 0; /* For reverb optimization */
/* Ring voice id for each notes. This ID enables duplicated note. */
static uint8 vidq_head[128 * MAX_CHANNELS], vidq_tail[128 * MAX_CHANNELS];
#ifdef MODULATION_WHEEL_ALLOW
int opt_modulation_wheel = 1;
#else
int opt_modulation_wheel = 0;
#endif /* MODULATION_WHEEL_ALLOW */
#ifdef PORTAMENTO_ALLOW
int opt_portamento = 1;
#else
int opt_portamento = 0;
#endif /* PORTAMENTO_ALLOW */
#ifdef NRPN_VIBRATO_ALLOW
int opt_nrpn_vibrato = 1;
#else
int opt_nrpn_vibrato = 0;
#endif /* NRPN_VIBRATO_ALLOW */
#ifdef REVERB_CONTROL_ALLOW
int opt_reverb_control = 1;
#else
int opt_reverb_control = 0;
#endif /* REVERB_CONTROL_ALLOW */
#ifdef CHORUS_CONTROL_ALLOW
int opt_chorus_control = 1;
#else
int opt_chorus_control = 0;
#endif /* CHORUS_CONTROL_ALLOW */
int opt_surround_chorus = 1;
#ifdef GM_CHANNEL_PRESSURE_ALLOW
int opt_channel_pressure = 1;
#else
int opt_channel_pressure = 0;
#endif /* GM_CHANNEL_PRESSURE_ALLOW */
#ifdef OVERLAP_VOICE_ALLOW
int opt_overlap_voice_allow = 1;
#else
int opt_overlap_voice_allow = 0;
#endif /* OVERLAP_VOICE_ALLOW */
/* TVA Env. Attack,Decay,Release... */
int opt_tva_attack = 0;
int opt_tva_decay = 0;
int opt_tva_release = 0;
int opt_delay_control = 0;
int opt_resonance = 0;
int opt_env_attack = 0; /* 0:linear, 1:exponential1, 2:exponential2, 3:logarithmic */
int voices=DEFAULT_VOICES, upper_voices;
int32
control_ratio=0,
amplification=DEFAULT_AMPLIFICATION;
static FLOAT_T
master_volume;
static int32 master_volume_ratio = 0xFFFF;
ChannelBitMask default_drumchannel_mask;
ChannelBitMask default_drumchannels;
ChannelBitMask drumchannel_mask;
ChannelBitMask drumchannels;
int adjust_panning_immediately=1;
int auto_reduce_polyphony=1;
double envelope_modify_rate = 1.0;
#if defined(CSPLINE_INTERPOLATION) || defined(LAGRANGE_INTERPOLATION)
int reduce_quality_flag=0;
int no_4point_interpolation=0;
#endif
char* pcm_alternate_file = NULL; /* NULL or "none": Nothing (default)
* "auto": Auto select
* filename: Use it
*/
static int32 lost_notes, cut_notes;
static int32 common_buffer[AUDIO_BUFFER_SIZE*2], /* stereo samples */
*buffer_pointer;
static int16 wav_buffer[AUDIO_BUFFER_SIZE*2];
static int32 buffered_count;
static char *reverb_buffer = NULL; /* MAX_CHANNELS*AUDIO_BUFFER_SIZE*8 */
static MidiEvent *event_list;
static MidiEvent *current_event;
static int32 sample_count; /* Length of event_list */
int32 current_sample; /* Number of calclated samples */
int note_key_offset = 0; /* For key up/down */
FLOAT_T midi_time_ratio = 1.0; /* For speed up/down */
static void update_portamento_controls(int ch);
static void update_rpn_map(int ch, int addr, int update_now);
static void ctl_prog_event(int ch);
static void ctl_timestamp(void);
static void ctl_updatetime(int32 samples);
static void ctl_pause_event(int pause, int32 samples);
static char *event_name(int type)
{
#define EVENT_NAME(X) case X: return #X
switch(type)
{
EVENT_NAME(ME_NONE);
EVENT_NAME(ME_NOTEOFF);
EVENT_NAME(ME_NOTEON);
EVENT_NAME(ME_KEYPRESSURE);
EVENT_NAME(ME_PROGRAM);
EVENT_NAME(ME_CHANNEL_PRESSURE);
EVENT_NAME(ME_PITCHWHEEL);
EVENT_NAME(ME_TONE_BANK_MSB);
EVENT_NAME(ME_TONE_BANK_LSB);
EVENT_NAME(ME_MODULATION_WHEEL);
EVENT_NAME(ME_BREATH);
EVENT_NAME(ME_FOOT);
EVENT_NAME(ME_MAINVOLUME);
EVENT_NAME(ME_BALANCE);
EVENT_NAME(ME_PAN);
EVENT_NAME(ME_EXPRESSION);
EVENT_NAME(ME_SUSTAIN);
EVENT_NAME(ME_PORTAMENTO_TIME_MSB);
EVENT_NAME(ME_PORTAMENTO_TIME_LSB);
EVENT_NAME(ME_PORTAMENTO);
EVENT_NAME(ME_PORTAMENTO_CONTROL);
EVENT_NAME(ME_DATA_ENTRY_MSB);
EVENT_NAME(ME_DATA_ENTRY_LSB);
EVENT_NAME(ME_SOSTENUTO);
EVENT_NAME(ME_SOFT_PEDAL);
EVENT_NAME(ME_HARMONIC_CONTENT);
EVENT_NAME(ME_RELEASE_TIME);
EVENT_NAME(ME_ATTACK_TIME);
EVENT_NAME(ME_BRIGHTNESS);
EVENT_NAME(ME_REVERB_EFFECT);
EVENT_NAME(ME_TREMOLO_EFFECT);
EVENT_NAME(ME_CHORUS_EFFECT);
EVENT_NAME(ME_CELESTE_EFFECT);
EVENT_NAME(ME_PHASER_EFFECT);
EVENT_NAME(ME_RPN_INC);
EVENT_NAME(ME_RPN_DEC);
EVENT_NAME(ME_NRPN_LSB);
EVENT_NAME(ME_NRPN_MSB);
EVENT_NAME(ME_RPN_LSB);
EVENT_NAME(ME_RPN_MSB);
EVENT_NAME(ME_ALL_SOUNDS_OFF);
EVENT_NAME(ME_RESET_CONTROLLERS);
EVENT_NAME(ME_ALL_NOTES_OFF);
EVENT_NAME(ME_MONO);
EVENT_NAME(ME_POLY);
#if 0
EVENT_NAME(ME_VOLUME_ONOFF); /* Not supported */
#endif
EVENT_NAME(ME_RANDOM_PAN);
EVENT_NAME(ME_SET_PATCH);
EVENT_NAME(ME_DRUMPART);
EVENT_NAME(ME_KEYSHIFT);
EVENT_NAME(ME_PATCH_OFFS);
EVENT_NAME(ME_TEMPO);
EVENT_NAME(ME_CHORUS_TEXT);
EVENT_NAME(ME_LYRIC);
EVENT_NAME(ME_GSLCD);
EVENT_NAME(ME_MARKER);
EVENT_NAME(ME_INSERT_TEXT);
EVENT_NAME(ME_TEXT);
EVENT_NAME(ME_KARAOKE_LYRIC);
EVENT_NAME(ME_MASTER_VOLUME);
EVENT_NAME(ME_RESET);
EVENT_NAME(ME_NOTE_STEP);
EVENT_NAME(ME_TIMESIG);
EVENT_NAME(ME_WRD);
EVENT_NAME(ME_SHERRY);
EVENT_NAME(ME_BARMARKER);
EVENT_NAME(ME_STEP);
EVENT_NAME(ME_LAST);
EVENT_NAME(ME_EOT);
}
return "Unknown";
#undef EVENT_NAME
}
static void adjust_amplification(void)
{
master_volume = (double)(amplification) / 100.0 *
((double)master_volume_ratio * (1.0/0xFFFF));
}
static int new_vidq(int ch, int note)
{
int i;
if(opt_overlap_voice_allow)
{
i = ch * 128 + note;
return vidq_head[i]++;
}
return 0;
}
static int last_vidq(int ch, int note)
{
int i;
if(opt_overlap_voice_allow)
{
i = ch * 128 + note;
if(vidq_head[i] == vidq_tail[i])
{
ctl->cmsg(CMSG_WARNING, VERB_DEBUG_SILLY,
"channel=%d, note=%d: Voice is already OFF", ch, note);
return -1;
}
return vidq_tail[i]++;
}
return 0;
}
static void reset_voices(void)
{
int i;
for(i = 0; i < MAX_VOICES; i++)
{
voice[i].status = VOICE_FREE;
voice[i].chorus_link = i;
}
upper_voices = 0;
memset(vidq_head, 0, sizeof(vidq_head));
memset(vidq_tail, 0, sizeof(vidq_tail));
}
static void kill_note(int i)
{
voice[i].status = VOICE_DIE;
if(!prescanning_flag)
ctl_note_event(i);
}
static void kill_all_voices(void)
{
int i, uv = upper_voices;
for(i = 0; i < uv; i++)
if(voice[i].status & ~(VOICE_FREE | VOICE_DIE))
kill_note(i);
memset(vidq_head, 0, sizeof(vidq_head));
memset(vidq_tail, 0, sizeof(vidq_tail));
}
static void reset_drum_controllers(struct DrumParts *d[], int note)
{
int i;
if(note == -1)
{
for(i = 0; i < 128; i++)
if(d[i] != NULL)
{
d[i]->drum_panning = NO_PANNING;
memset(d[i]->drum_envelope_rate, 0,
sizeof(d[i]->drum_envelope_rate));
d[i]->pan_random = 0;
d[i]->drum_level = 1;
d[i]->note = 0;
d[i]->delay_level = 0;
d[i]->chorus_level = 0;
d[i]->reverb_level = 0;
}
}
else
{
d[note]->drum_panning = NO_PANNING;
memset(d[note]->drum_envelope_rate, 0,
sizeof(d[note]->drum_envelope_rate));
d[note]->pan_random = 0;
d[note]->drum_level = 1;
d[note]->note = 0;
d[note]->delay_level = 0;
d[note]->chorus_level = 0;
d[note]->reverb_level = 0;
}
}
/* Process the Reset All Controllers event */
static void reset_controllers(int c)
{
/* Some standard says, although the SCC docs say 0. */
if(play_system_mode == XG_SYSTEM_MODE)
channel[c].volume = 100;
else
channel[c].volume = 90;
channel[c].expression=127; /* SCC-1 does this. */
channel[c].sustain=0;
channel[c].pitchbend=0x2000;
channel[c].pitchfactor=0; /* to be computed */
channel[c].modulation_wheel = 0;
channel[c].portamento_time_lsb = 0;
channel[c].portamento_time_msb = 0;
channel[c].porta_control_ratio = 0;
channel[c].portamento = 0;
channel[c].last_note_fine = -1;
reset_drum_controllers(channel[c].drums, -1);
channel[c].vibrato_ratio = 0;
channel[c].vibrato_depth = 0;
channel[c].vibrato_delay = 0;
memset(channel[c].envelope_rate, 0, sizeof(channel[c].envelope_rate));
update_portamento_controls(c);
set_reverb_level(c, -1);
if(opt_chorus_control == 1)
channel[c].chorus_level = 0;
else
channel[c].chorus_level = -opt_chorus_control;
channel[c].mono = 0;
channel[c].delay_level = 0;
channel[c].resonance_level = 0;
}
static void redraw_controllers(int c)
{
ctl_mode_event(CTLE_VOLUME, 1, c, channel[c].volume);
ctl_mode_event(CTLE_EXPRESSION, 1, c, channel[c].expression);
ctl_mode_event(CTLE_SUSTAIN, 1, c, channel[c].sustain);
ctl_mode_event(CTLE_MOD_WHEEL, 1, c, channel[c].modulation_wheel);
ctl_mode_event(CTLE_PITCH_BEND, 1, c, channel[c].pitchbend);
ctl_prog_event(c);
ctl_mode_event(CTLE_CHORUS_EFFECT, 1, c, get_chorus_level(c));
ctl_mode_event(CTLE_REVERB_EFFECT, 1, c, get_reverb_level(c));
}
static void reset_midi(int playing)
{
int i;
for(i = 0; i < MAX_CHANNELS; i++)
{
reset_controllers(i);
/* The rest of these are unaffected by the Reset All Controllers
event */
channel[i].program = default_program[i];
channel[i].panning = NO_PANNING;
channel[i].pan_random = 0;
/* tone bank or drum set */
if(ISDRUMCHANNEL(i))
{
channel[i].bank = 0;
channel[i].altassign = drumset[0]->alt;
}
else
{
if(special_tonebank >= 0)
channel[i].bank = special_tonebank;
else
channel[i].bank = default_tonebank;
}
channel[i].bank_lsb = channel[i].bank_msb = 0;
if(play_system_mode == XG_SYSTEM_MODE && i % 16 == 9)
channel[i].bank_msb = 127; /* Use MSB=127 for XG */
update_rpn_map(i, RPN_ADDR_FFFF, 0);
channel[i].special_sample = 0;
channel[i].key_shift = 0;
channel[i].mapID = get_default_mapID(i);
channel[i].lasttime = 0;
}
if(playing)
{
kill_all_voices();
for(i = 0; i < MAX_CHANNELS; i++)
redraw_controllers(i);
}
else
reset_voices();
master_volume_ratio = 0xFFFF;
adjust_amplification();
if(current_file_info)
{
memcpy(&drumchannels, ¤t_file_info->drumchannels,
sizeof(ChannelBitMask));
memcpy(&drumchannel_mask, ¤t_file_info->drumchannel_mask,
sizeof(ChannelBitMask));
}
else
{
memcpy(&drumchannels, &default_drumchannels, sizeof(ChannelBitMask));
memcpy(&drumchannel_mask, &default_drumchannel_mask,
sizeof(drumchannels));
}
ctl_mode_event(CTLE_MASTER_VOLUME, 0, amplification, 0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -