+2003-07-06 TAMUKI Shoichi <tamuki@linet.gr.jp>
+
+ * timidity/playmidi.[ch], timidity/readmidi.c, timidity/tables.[ch],
+ timidity/timidity.c:
+ Support for single-note tuning change
+ Support for channel mute by user-defined temperament type
+ Fix around temperament type redrawing on ME_RESET
+ Fix around channel mute by temperament type on ME_RESET
+
2003-07-03 TAMUKI Shoichi <tamuki@linet.gr.jp>
* timidity/playmidi.c, timidity/tables.[ch], timidity/timidity.c:
static void ctl_pause_event(int pause, int32 samples);
static void update_legato_controls(int ch);
static void update_channel_freq(int ch);
+static void set_single_note_tuning(int, int, int);
#define IS_SYSEX_EVENT_TYPE(type) ((type) == ME_NONE || (type) >= ME_RANDOM_PAN)
EVENT_NAME(ME_TIMESIG);
EVENT_NAME(ME_KEYSIG);
EVENT_NAME(ME_SCALE_TUNING);
+ EVENT_NAME(ME_SINGLE_NOTE_TUNING);
EVENT_NAME(ME_TEMPER_KEYSIG);
EVENT_NAME(ME_TEMPER_TYPE);
EVENT_NAME(ME_MASTER_TEMPER_TYPE);
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_TEMPER_TYPE, 1, c, channel[c].temper_type);
+ ctl_mode_event(CTLE_MUTE, 1,
+ c, (IS_SET_CHANNELMASK(channel_mute, c)) ? 1 : 0);
ctl_mode_event(CTLE_CHORUS_EFFECT, 1, c, get_chorus_level(c));
ctl_mode_event(CTLE_REVERB_EFFECT, 1, c, get_reverb_level(c));
}
}
if (playing) {
kill_all_voices();
+ if (temper_type_mute) {
+ if (temper_type_mute & 1)
+ FILL_CHANNELMASK(channel_mute);
+ else
+ CLEAR_CHANNELMASK(channel_mute);
+ }
for (i = 0; i < MAX_CHANNELS; i++)
redraw_controllers(i);
if (midi_streaming && free_instruments_afterwards) {
master_volume_ratio = 0xFFFF;
adjust_amplification();
+ init_freq_table_tuning();
if(current_file_info)
{
COPY_CHANNELMASK(drumchannels, current_file_info->drumchannels);
if (! opt_pure_intonation && voice[v].temper_instant) {
switch (tt) {
case 0:
- f = freq_table[note];
+ f = freq_table_tuning[0][note];
break;
case 1:
f = freq_table_pytha[current_freq_table][note];
else
f = freq_table_user[tt][current_freq_table + 12][note];
} else
- f = freq_table[note];
+ f = freq_table_tuning[0][note];
break;
}
voice[v].orig_frequency = f;
} else
switch (tt) {
case 0:
- f = freq_table[note];
+ f = freq_table_tuning[0][note];
break;
case 1:
f = freq_table_pytha[current_freq_table][note];
else
f = freq_table_user[tt][current_freq_table + 12][note];
} else
- f = freq_table[note];
+ f = freq_table_tuning[0][note];
break;
}
fs = freq_table[note];
channel[ch].scale_tuning[current_event->a] = current_event->b;
break;
+ case ME_SINGLE_NOTE_TUNING:
+ set_single_note_tuning(ch, current_event->a, current_event->b);
+ break;
+
case ME_TEMPER_KEYSIG:
current_temper_keysig = current_event->a;
break;
adjust_pitch(ch);
break;
+ case ME_SINGLE_NOTE_TUNING:
+ set_single_note_tuning(ch, current_event->a, current_event->b);
+ for (i = 0; i < upper_voices; i++)
+ if (voice[i].status != VOICE_FREE) {
+ voice[i].temper_instant = 1;
+ recompute_freq(i);
+ }
+ break;
+
case ME_TEMPER_KEYSIG:
current_temper_keysig = current_event->a;
ctl_mode_event(CTLE_TEMPER_KEYSIG, 1, current_temper_keysig, 0);
case ME_TEMPER_TYPE:
channel[ch].temper_type = current_event->a;
ctl_mode_event(CTLE_TEMPER_TYPE, 1, ch, channel[ch].temper_type);
+ current_event->a -= (current_event->a >= 0x40) ? 0x3c : 0;
if (temper_type_mute) {
if (temper_type_mute & 1 << current_event->a) {
SET_CHANNELMASK(channel_mute, ch);
channel[i].temper_type = current_event->a;
ctl_mode_event(CTLE_TEMPER_TYPE, 1, i, channel[i].temper_type);
}
+ current_event->a -= (current_event->a >= 0x40) ? 0x3c : 0;
if (temper_type_mute) {
if (temper_type_mute & 1 << current_event->a) {
FILL_CHANNELMASK(channel_mute);
return RC_NONE;
}
+static void set_single_note_tuning(int part, int a, int b)
+{
+ static int tp; /* tuning program number */
+ static int kn; /* MIDI key number */
+ static int st; /* the nearest equal-tempered semitone */
+ double f, fst; /* fraction of seminote */
+
+ switch (part) {
+ case 0:
+ tp = a;
+ break;
+ case 1:
+ kn = a;
+ st = b;
+ break;
+ case 2:
+ if (st == 0x7f && a == 0x7f && b == 0x7f) /* no change */
+ break;
+ f = 440 * pow(2.0, (st - 69) / 12.0);
+ fst = pow(2.0, (a << 7 | b | ((a & 0x40) ? 0xc000 : 0)) / 98304.0);
+ freq_table_tuning[tp][kn] = f * fst * 1000 + 0.5;
+ break;
+ }
+}
+
static int play_midi(MidiEvent *eventlist, int32 samples)
{
int rc;
ME_TIMESIG, /* Time signature */
ME_KEYSIG, /* Key signature */
ME_SCALE_TUNING, /* Scale tuning */
+ ME_SINGLE_NOTE_TUNING, /* Single-note tuning */
ME_TEMPER_KEYSIG, /* Temperament key signature */
ME_TEMPER_TYPE, /* Temperament type */
ME_MASTER_TEMPER_TYPE, /* Master Temperament type */
case 65: type = ME_PORTAMENTO; break;
case 66: type = ME_SOSTENUTO; break;
case 67: type = ME_SOFT_PEDAL; break;
- case 68: type = ME_LEGATO_FOOTSWITCH; break;
- case 69: type = ME_HOLD2; break;
+ case 68: type = ME_LEGATO_FOOTSWITCH; break;
+ case 69: type = ME_HOLD2; break;
case 71: type = ME_HARMONIC_CONTENT; break;
case 72: type = ME_RELEASE_TIME; break;
case 73: type = ME_ATTACK_TIME; break;
int parse_sysex_event_multi(uint8 *val, int32 len, MidiEvent *evm)
{
int num_events = 0; /* Number of events added */
- uint16 channel_st;
+ uint16 channel_tt;
int i, j;
if(current_file_info->mid == 0 || current_file_info->mid >= 0x7e)
break;
case 0x08: /* MIDI Tuning Standard */
switch (val[3]) {
+ case 0x02:
+ SETMIDIEVENT(evm[0], 0, ME_SINGLE_NOTE_TUNING,
+ 0, val[4], 0);
+ for (i = 0; i < val[5]; i++) {
+ SETMIDIEVENT(evm[i * 2 + 1], 0, ME_SINGLE_NOTE_TUNING,
+ 1, val[6], val[7]);
+ SETMIDIEVENT(evm[i * 2 + 2], 0, ME_SINGLE_NOTE_TUNING,
+ 2, val[8], val[9]);
+ }
+ num_events = val[5] * 2 + 1;
+ break;
case 0x0b:
- channel_st = val[4] << 14 | val[5] << 7 | val[6];
+ channel_tt = val[4] << 14 | val[5] << 7 | val[6];
if (val[1] == 0x7f) {
SETMIDIEVENT(evm[0], 0, ME_MASTER_TEMPER_TYPE,
0, val[7], (val[0] == 0x7f) ? 1 : 0);
num_events++;
} else {
for (i = 0, j = 0; i < 16; i++)
- if (channel_st & 1 << i) {
+ if (channel_tt & 1 << i) {
SETMIDIEVENT(evm[j], 0, ME_TEMPER_TYPE,
MERGE_CHANNEL_PORT(i),
val[7], (val[0] == 0x7f) ? 1 : 0);
bank_lsb[ch] = meep->event.a;
break;
- case ME_CHORUS_TEXT:
+ case ME_CHORUS_TEXT:
case ME_LYRIC:
case ME_MARKER:
case ME_INSERT_TEXT:
#include "tables.h"
int32 freq_table[128];
+int32 freq_table_tuning[128][128];
int32 freq_table_pytha[12][128];
int32 freq_table_meantone[24][128];
int32 freq_table_pureint[24][128];
freq_table[i] = 440 * pow(2.0, (i - 69) / 12.0) * 1000 + 0.5;
}
+void init_freq_table_tuning(void)
+{
+ int p, i;
+ double f;
+
+ for (i = 0; i < 128; i++) {
+ f = 440 * pow(2.0, (i - 69) / 12.0);
+ for (p = 0; p < 128; p++)
+ freq_table_tuning[p][i] = f * 1000 + 0.5;
+ }
+}
+
void init_freq_table_pytha(void)
{
int i, j, k, l;
#define SINE_CYCLE_LENGTH 1024
extern int32 freq_table[];
+extern int32 freq_table_tuning[][128];
extern int32 freq_table_pytha[][128];
extern int32 freq_table_meantone[][128];
extern int32 freq_table_pureint[][128];
extern FLOAT_T reverb_time_table[];
extern void init_freq_table(void);
+extern void init_freq_table_tuning(void);
extern void init_freq_table_pytha(void);
extern void init_freq_table_meantone(void);
extern void init_freq_table_pureint(void);
case 'Q':
if (strchr(optarg, 't')) {
- if (set_value(&tmpi32, atoi(optarg), 0, 3, "Quiet temperament"))
+ if (set_value(&tmpi32, atoi(optarg), 0, 7, "Quiet temperament"))
return 1;
temper_type_mute |= 1 << tmpi32;
} else
url_add_module(url_module_list[i]);
init_string_table(&opt_config_string);
init_freq_table();
+ init_freq_table_tuning();
init_freq_table_pytha();
init_freq_table_meantone();
init_freq_table_pureint();