📄 mod2midi.c
字号:
/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2002 Masanao Izumo <mo@goice.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 mod2midi.c Mixer event -> MIDI event conversion*/#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include "timidity.h"#include "common.h"#include "instrum.h"#include "playmidi.h"#include "readmidi.h"#include "tables.h"#include "mod.h"#include "output.h"#include "controls.h"#include "unimod.h"#include "mod2midi.h"#include "filter.h"#include "math.h"#include "freq.h"/* Define this to show all the notes touched by a bending in the * user interface's trace view. This is interesting but disabled * because it needs tons of CPU power (tens of voices are activated * but unaudible). *//* #define TRACE_SLIDE_NOTES *//* Define this to give a volume envelope to a MOD's notes. This * could sound wrong with a few MODs, but gives richer sound most * of the time. */#define USE_ENVELOPE#define SETMIDIEVENT(e, at, t, ch, pa, pb) \ { /* printf("%d %d " #t " %d %d\n", at, ch, pa, pb); */ \ (e).time = (at); (e).type = (t); \ (e).channel = (uint8)(ch); (e).a = (uint8)(pa); (e).b = (uint8)(pb); }#define MIDIEVENT(at, t, ch, pa, pb) \ { MidiEvent event; SETMIDIEVENT(event, at, t, ch, pa, pb); \ readmidi_add_event(&event); }/* Clock SampleRate := ---------- Period */#define NTSC_CLOCK 3579545.25#define NTSC_RATE ((int32)(NTSC_CLOCK/428))#define PAL_CLOCK 3546894.6#define PAL_RATE ((int32)(PAL_CLOCK/428))#define MOD_ROOT_NOTE 36/* The internal bending register is 21-bits wide and it is made like this: * _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ * | | | | | | | | | | | | | | | | | | | | | | * | 8 bits | 8 bits | 5 bits | * | note shift | fine tune |discarded| * '---------------'---------------'---------' * * The note shift is an `offset' field: 128 = keep this note. * To compute it, the values given to the pitch-wheel MIDI event are * multiplied by the sensitivity. We want to be able to express a full * 120 notes bending (8 bits for the note shift + 8 for the fine tune) * with 14-bit pitch-wheel event, so we want a sensitivity value that * forces the bottom 7 bits of the internal register to 0. This value * is of course 128. */#define WHEEL_SENSITIVITY (1 << 7)#define WHEEL_VALUE(bend) ((bend) / WHEEL_SENSITIVITY + 0x2000)typedef struct _ModVoice { int sample; /* current sample ID */ int noteon; /* (-1 means OFF status) */ int time; /* time when note was activated */ int period; /* current frequency */ int wheel; /* current pitch wheel value */ int pan; /* current panning */ int vol; /* current volume */ int32 noteson[4]; /* bit map for notes 0-127 */ }ModVoice;static void mod_change_tempo (int32 at, int bpm);static int period2note (int period, int *finetune);static ModVoice ModV[MOD_NUM_VOICES];static int at;/******************** bitmap handling macros **********************************/#define bitmapGet(map, n) ((map)[(n) >> 5] & (1 << ((n) & 31)))#define bitmapSet(map, n) ((map)[(n) >> 5] |= (1 << ((n) & 31)))#define bitmapClear(map) ((map)[0] = (map)[1] = (map)[2] = (map)[3] = 0)static char significantDigitsLessOne[256] = { -1, /* 1 */ 0, /* 2 */ 1, 1, /* 4 */ 2, 2, 2, 2, /* 8 */ 3, 3, 3, 3, 3, 3, 3, 3, /* 16 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* 32 */ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* 64 */ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, /* 128 */ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 256 */ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};/******************************************************************************/voidmod_change_tempo (int32 at, int bpm){ int32 tempo; int c, a, b; tempo = 60000000 / bpm; c = (tempo & 0xff); a = ((tempo >> 8) & 0xff); b = ((tempo >> 16) & 0xff); MIDIEVENT (at, ME_TEMPO, c, b, a);}intperiod2note (int period, int *finetune){ static int period_table[121] = { /* C C# D D# E F F# G G# A A# B */ 13696,12928,12192,11520,10848,10240, 9664, 9120, 8608, 8096, 7680, 7248, 6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4048, 3840, 3624, 3424, 3232, 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2024, 1920, 1812, 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906, 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, 107, 101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56, 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28, 27, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14, -100 /* just a guard */ }; int note; int l, r, m; if (period < 14 || period > 13696) { ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "BAD period %d\n", period); return -1; } /* bin search */ l = 0; r = 120; while (l < r) { m = (l + r) / 2; if (period_table[m] >= period) l = m + 1; else r = m; } note = l - 1; /* * 112 >= note >= 0 * period_table[note] >= period > period_table[note + 1] */ if (period_table[note] == period) *finetune = 0; else { /* Pick the closest note even if it is higher than this one. * (e.g. 721 - 720 < 762 - 721 ----> pick 720) */ if (period - period_table[note + 1] < period_table[note] - period) note++; /* fine tune completion */ *finetune = ((period_table[note] - period) << 8) / (period_table[note] - period_table[note + 1]); *finetune <<= 5; } return note;}/********** Interface to mod.c */voidVoice_SetVolume (UBYTE v, UWORD vol){ if (v >= MOD_NUM_VOICES) return; /* MOD volume --> MIDI volume */ vol >>= 1; /* if (vol < 0) vol = 0; *//* UNSIGNED! */ if (vol > 127) vol = 127; if (ModV[v].vol != vol) { ModV[v].vol = vol; MIDIEVENT (at, ME_EXPRESSION, v, vol, 0); }}voidVoice_SetPeriod (UBYTE v, ULONG period){ int new_noteon, bend; if (v >= MOD_NUM_VOICES) return; ModV[v].period = period; if (ModV[v].noteon < 0) return; new_noteon = period2note (ModV[v].period, &bend);#ifndef TRACE_SLIDE_NOTES bend += (new_noteon - ModV[v].noteon) << 13; new_noteon = ModV[v].noteon;#endif bend = WHEEL_VALUE(bend); if (ModV[v].noteon != new_noteon) { MIDIEVENT(at, ME_KEYPRESSURE, v, ModV[v].noteon, 1); if (new_noteon < 0) { ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Strange period %d", ModV[v].period); return; } else if (!bitmapGet(ModV[v].noteson, new_noteon)) { MIDIEVENT(ModV[v].time, ME_NOTEON, v, new_noteon, 1); bitmapSet(ModV[v].noteson, new_noteon); } } if (ModV[v].wheel != bend) { ModV[v].wheel = bend; MIDIEVENT (at, ME_PITCHWHEEL, v, bend & 0x7F, (bend >> 7) & 0x7F); } if (ModV[v].noteon != new_noteon) { MIDIEVENT(at, ME_KEYPRESSURE, v, new_noteon, 127); ModV[v].noteon = new_noteon; }}voidVoice_SetPanning (UBYTE v, ULONG pan){ if (v >= MOD_NUM_VOICES) return; if (pan == PAN_SURROUND) pan = PAN_CENTER; /* :-( */ if (pan != ModV[v].pan) { ModV[v].pan = pan; MIDIEVENT(at, ME_PAN, v, pan * 127 / PAN_RIGHT, 0); }}voidVoice_Play (UBYTE v, SAMPLE * s, ULONG start){ int new_noteon, bend; if (v >= MOD_NUM_VOICES) return; if (ModV[v].noteon != -1) Voice_Stop (v); new_noteon = period2note (ModV[v].period, &bend); bend = WHEEL_VALUE(bend); if (new_noteon < 0) { ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Strange period %d", ModV[v].period); return; } ModV[v].noteon = new_noteon; ModV[v].time = at; bitmapSet(ModV[v].noteson, new_noteon); if (ModV[v].sample != s->id) { ModV[v].sample = s->id; MIDIEVENT(at, ME_SET_PATCH, v, ModV[v].sample, 0); } if (start > 0) { int a, b;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -