⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m2m.c

📁 MIDI解码程序(用VC编写)
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    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*//* * EAW -- Quick and dirty hack to convert the TiMidity events generated from * a MOD file into events suitable for writing to a midi file, then write * the midi file. * * DONE LIST (various odd things needed for MOD->MIDI format conversion): *  1) MIDI does not support pitch bends > 2 octaves... *     scale pitch bends for a sensitivy of 24 instead of 128, *     pitch bends > 2 octaves wrapped back an octave and continue as normal *  2) moved all drum voices onto the drum channel, and all non-drum voices *     off of the drum channel to the first available channel (which could be *     a channel that has been freed by moving all of it's drum voices off *     of it) *  3) moved/duped events on to other channels to handle the drum related stuff *  4) force all drums to center pan, since drums originally on different *     channels could mess up each other's pans when they are merged on to a *     single channel *  5) added in extra stuff to keep track of and scale expression events as *     necessary, so that each sample can have it's own amplification setting *  6) turn all drum channel expression stuff into initial note volumes *  7) experimented with turning expression events into keypressure events, *     but this didn't sound good, because my XG card doesn't handle increases *     in keypressure, and the expression events are also needed to boost the *     volumes of note decays (since keypressure doesn't work on dead notes) *  8) emit chords for chord samples *  9) issue bank change events, as specified in the cfg file * 10) ignore redundant program changes, which often happen from drum moves * 11) ability to silence a sample, so it emits no note or program events * 12) issue port events to make midi with > 16 channels * 13) skip over the drum channel on the 2nd port * 14) kill non-looped mod samples when the play past sample end * 15) extended bend range to 4 octaves using note+pitchbend shifting * 16) automatic sample chord/pitch assignment and cfg file generation !!! :) * 17) can offset pitchbends to undo out of tune sample tuning (detuning) * 18) converts linear mod volumes into non-linear midi volumes * 19) other more minor things that may or may not be commented * * TODO LIST (likely to be done eventually) *  1) correctly implement fine tuning tweaks via extra pitch bends *  2) maybe issue a SYSEX event to make channel 26 non-drum for regular use? *  3) clean up the code some more * * WISH LIST (far less likely to ever be done): *  1) make an alternate output mode that outputs a separate track for every *     combination of sample and channel it is used on *  2) possibly have an automated channel merger, but it might have to strip *     out some pans, expression events, and pitch bends to do it *  3) maybe handle > 4 octave pitch bends in a better way */#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include <stdio.h>#include <stdlib.h>#include <math.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 "output.h"#include "controls.h"#include "tables.h"#include "freq.h"static char *outname = NULL;static char *actual_outname;static char *cfgname = NULL;static unsigned char header[14] = { 0x4D, 0x54, 0x68, 0x64,    0x00, 0x00, 0x00, 0x06,    0x00, 0x01, 0x00, 0x00,    0x00, 0x00};static unsigned char mtrk[4] = { 0x4D, 0x54, 0x72, 0x6B };static unsigned char event[11];static unsigned char dt_array[4];static unsigned char *track_events[34];static unsigned char *p_track_event;static uint32 last_track_event_time[34];static uint32 track_size[34];static int tracks_enabled[34];static int tracks_useless[34];static int current_track_sample[34];static int orig_track_expr[34];static int current_channel_expr[34];static int current_channel_bank[34];static int current_channel_program[34];static int current_channel_note[34];static int current_track_note[34];static int track_pans[34];static uint32 kill_early_time[34];static int kill_early_note[34];static int kill_early_velocity[34];static int kill_early_ch[34];static int tweak_note_offset[34];static int tweak_pb_offset[34];static uint32 length;static uint16 divisions, orig_divisions;static double divisions_ratio;static int num_dt_bytes;static int32 value;static int num_tracks = 0;static int32 tempo = 500000;static uint32 maxtime = 0;static uint32 num_killed_early = 0;static uint32 num_big_pitch_slides = 0;static uint32 num_huge_pitch_slides = 0;static int pb_sensitivity = 24;static int old_pb_sensitivity = 128;static float notes_per_pb = 24.0 / 8191.0;static float pb_per_note = 8191.0 / 24.0;static int rpn_msb = 0, rpn_lsb = 0;static int min_enabled_track = -1, max_enabled_track, first_free_track = -1;static int non_drums_on_drums = 0;#define MAX_PB_SENSITIVITY 24static int silent_samples[256];static int sample_chords[256];static int sample_to_program[256];static int banks[256];static int transpose[256];static int is_drum_sample[256];static int vol_amp[256];static char linestring[256];static int fine_tune[256];static double samples_per_tick;static int maxsample;static char chord_letters[4] = { 'M', 'm', 'd', 'f' };#define ROUND(frac)			(floor(frac + 0.5))/* mod volumes are linear, midi volumes are x^1.66 (for generic hardware) * scale the mod volumes so they sound linear on non-linear midi devices * EXPRESSION events are the new corrected volume levels * MAINVOLUME events fine tune the volume correction * * lookup_table[mod_vol][expression, volume] */static char vol_nonlin_to_lin[128][2] = {      0, 127,   7, 125,  11, 120,  14, 121,  16, 126,  19, 121,  21, 122,     23, 122,  25, 122,  26, 126,  28, 125,  30, 123,  31, 126,  33, 124,     34, 126,  36, 124,  37, 125,  38, 126,  40, 124,  41, 125,  42, 126,     43, 127,  45, 125,  46, 125,  47, 126,  48, 126,  49, 127,  50, 127,     52, 125,  53, 125,  54, 125,  55, 125,  56, 126,  57, 126,  58, 126,     59, 126,  60, 126,  61, 126,  62, 126,  63, 126,  64, 126,  65, 126,     66, 126,  67, 125,  68, 125,  69, 125,  69, 127,  70, 127,  71, 126,     72, 126,  73, 126,  74, 126,  75, 126,  76, 125,  76, 127,  77, 127,     78, 126,  79, 126,  80, 126,  81, 126,  81, 127,  82, 126,  83, 126,     84, 126,  85, 126,  85, 127,  86, 126,  87, 126,  88, 126,  88, 127,     89, 127,  90, 126,  91, 126,  91, 127,  92, 127,  93, 126,  94, 126,     94, 127,  95, 127,  96, 126,  97, 126,  97, 127,  98, 126,  99, 126,    100, 126, 100, 127, 101, 126, 102, 126, 102, 127, 103, 126, 104, 126,    104, 127, 105, 127, 106, 126, 106, 127, 107, 127, 108, 126, 108, 127,    109, 127, 110, 126, 110, 127, 111, 127, 112, 126, 112, 127, 113, 127,    114, 126, 114, 127, 115, 127, 116, 126, 116, 127, 117, 126, 118, 126,    118, 127, 119, 126, 120, 126, 120, 127, 121, 126, 121, 127, 122, 126,    123, 126, 123, 127, 124, 126, 124, 127, 125, 127, 126, 126, 126, 127,    127, 126, 127, 127 };/* * Uses the volume curve specified by the -V or --volume-curve option. * * The resulting midi will sound correct on hardware / software that uses * the volume curve selected by the user. * * -V 1.661, or (1/log10(4)), is the default timidity volume curve for GM/XG, * and is thus the default for MOD->MIDI output as well, so that the * resulting midi will sound correct when played using default timidity * options. * * -V 2 should be used to generate midi for playback on MIDI hardware, since * the GM/GS/XG standards all specify a volume curve of X^2 * * -V 1.661 will still sound good on MIDI hardware, though, and should sound * better than -V 2 on softsynths that (incorrectly) use linear volume curves * (such as TiMidity++ versions <= 2.11.3). * * Use -V 1 if you want to generate midi ONLY for linear volume devices. * It will sound bad when played with anything else. */void fill_vol_nonlin_to_lin_table(void){    int i;    int coarse, fine;    double power = 0;    double inverse;    double temp;    double log_127;    /* derive the power used to generate the user volume table */    log_127 = log(127);    for (i = 1; i <= 126; i++)    	power += (log(user_vol_table[i]) - log_127) / (log(i) - log_127);    power /= 126;    /* use the inverse of the power to generate the new table */    for (i = 1; i <= 127; i++)    {    	inverse = pow(i / 127.0, 1.0 / power);       	temp = 127 * inverse;    	coarse = floor(temp + 0.5);	if (coarse < temp) coarse += 1;	fine = floor(127 * temp / coarse + 0.5);	vol_nonlin_to_lin[i][0] = coarse;	vol_nonlin_to_lin[i][1] = fine;    }}/* generate the names of the output and cfg files from the input file *//* modified from auto_wav_output_open() in wave_a.c */static int auto_names(const char *input_filename){    char *ext, *p;    outname = (char *) safe_realloc(outname,			       sizeof(char) * (strlen(input_filename) + 5));    cfgname = (char *) safe_realloc(cfgname,			       sizeof(char) * (strlen(input_filename) + 5));    strcpy(outname, input_filename);    if ((ext = strrchr(outname, '.')) == NULL)	ext = outname + strlen(outname);    else    {	/* strip ".???" */	*ext = '\0';    }    /* replace '.' and '#' before ext */    for (p = outname; p < ext; p++)	if (*p == '.' || *p == '#')	    *p = '_';    strcpy(cfgname, outname);    strcat(outname, ".mid");    strcat(cfgname, ".m2m");    actual_outname = outname;    return 0;}void initialize_m2m_stuff(void){    int i;    memset(track_events, 0, 34 * sizeof(unsigned char *));    memset(last_track_event_time, 0, 34 * sizeof(uint32));    memset(track_size, 0, 34 * sizeof(uint32));    memset(tracks_enabled, 0, 34 * sizeof(int));    memset(tracks_useless, 0, 34 * sizeof(int));    memset(current_track_sample, 0, 34 * sizeof(int));    memset(orig_track_expr, 0, 34 * sizeof(int));    memset(current_channel_expr, 0, 34 * sizeof(int));    memset(current_channel_bank, 0, 34 * sizeof(int));    memset(current_channel_program, 0, 34 * sizeof(int));    memset(current_channel_note, 0, 34 * sizeof(int));    memset(current_track_note, 0, 34 * sizeof(int));    memset(banks, 0, 256 * sizeof(int));    memset(transpose, 0, 256 * sizeof(int));    memset(is_drum_sample, 0, 256 * sizeof(int));    memset(silent_samples, 0, 256 * sizeof(int));    memset(fine_tune, 0, 256 * sizeof(int));    /* get the names of the output and cfg files */    auto_names(current_file_info->filename);    if (play_mode->name != NULL)	actual_outname = play_mode->name;    ctl->cmsg(CMSG_INFO, VERB_NORMAL, "Output %s", actual_outname);    for (i = 0; i < 256; i++)    {	sample_to_program[i] = i;	if (i > 127)	    sample_to_program[i] = i - 127;	sample_chords[i] = -1;	vol_amp[i] = 100;    }    for (i = 0; i < 34; i++)    {	tracks_useless[i] = 1;	current_track_sample[i] = 255;	current_channel_note[i] = -1;	current_track_note[i] = -1;    }    /* support to increase the number of divisions, this may be useful */    orig_divisions = current_file_info->divisions;    divisions = 480;		/* maximum number of divisions */    divisions_ratio = (divisions / orig_divisions);    num_tracks = 0;    tempo = 500000;    maxtime = 0;    num_killed_early = 0;    num_big_pitch_slides = 0;    num_huge_pitch_slides = 0;    pb_sensitivity = 24;    old_pb_sensitivity = 128;    notes_per_pb = 24.0 / 8191.0;    pb_per_note = 8191.0 / 24.0;    rpn_msb = 0;    rpn_lsb = 0;    min_enabled_track = -1;    first_free_track = -1;    non_drums_on_drums = 0;    for (i = 1, maxsample = 0; i < 256; i++)    {	if (special_patch[i])	    maxsample = i;    }}int create_m2m_cfg_file(char *cfgname){    FILE *cfgout;    int i, chord, chord_type, chord_subtype;    char line[81];    char chord_str[3];    char program_str[17];    cfgout = fopen(cfgname, "wb");    if (!cfgout)    {	ctl->cmsg(CMSG_INFO, VERB_NORMAL,		  "Could not open cfg file %s for writing", cfgname);	return 0;    }    fprintf(cfgout, "%s\t%s\t\t%s\t%s\t%s\n\n",    	    "# Sample", "Program", "Transpose", "FineTuning", "%Volume");    for (i = 1; i <= maxsample; i++)    {	memset(chord_str, 0, 3 * sizeof(char));	if (special_patch[i])	{	    chord = sample_chords[i];	    if (chord >= 0)	    {		chord_type = chord / 3;		chord_subtype = chord % 3;		chord_str[0] = chord_letters[chord_type];		if (chord_subtype)		    chord_str[1] = '0' + chord_subtype;	    }	    sprintf(program_str, "%d%s", sample_to_program[i], chord_str);	    sprintf(line, "%d\t\t%s\t\t%d\t\t!%.6f\t100\n",		    i, program_str, transpose[i],		    fine_tune[i] * notes_per_pb);	}	else	{	    sprintf(line, "# %d unused\n", i);	}	fprintf(cfgout, "%s", line);    }    fclose(cfgout);    return 1;}void read_m2m_cfg_file(void){    FILE *mod_cfg_file;    float freq;    int i, pitch;    char *chord_str;    int chord, chord_type, chord_subtype;    char line[81];    int mod_sample, program, trans, amp;    char program_str[20], finetune_str[20];    char *slash_pos;    /* read in cfg file stuff, create new one if doesn't exist */    mod_cfg_file = fopen(cfgname, "rb");    if (!mod_cfg_file)    {	ctl->cmsg(CMSG_INFO, VERB_NORMAL,		  "Couldn't open '%s' cfg file.  Creating %s ...", cfgname,		  cfgname);	for (i = 1; i <= maxsample; i++)	{	    if (special_patch[i])	    {		chord = special_patch[i]->sample->chord;		freq = special_patch[i]->sample->root_freq_detected;		pitch = assign_pitch_to_freq(freq);		fine_tune[i] = (-36.37631656f +				 17.31234049f * log(freq) - pitch) *				 pb_per_note;		sprintf(line,			"Sample %3d Freq %10.4f Pitch %3d Transpose %4d",			i, freq, pitch,			special_patch[i]->sample->transpose_detected);		if (chord >= 0)		{		    sprintf(line, "%s Chord %c Subtype %d",			    line, chord_letters[chord / 3], chord % 3);		}		ctl->cmsg(CMSG_INFO, VERB_NORMAL, "%s", line);		transpose[i] = special_patch[i]->sample->transpose_detected;		sample_chords[i] = chord;	    }	}	create_m2m_cfg_file(cfgname);	mod_cfg_file = fopen(cfgname, "rb");    }    if (mod_cfg_file)    {	while (fgets(linestring, 256, mod_cfg_file) != NULL)	{	    if (*linestring == '#' || *linestring == '\n' ||		*linestring == '\r')		    continue;	    sscanf(linestring, "%d %s %d %s %d\n",		   &mod_sample, program_str, &trans, finetune_str, &amp);	    if (strchr(program_str, '!'))	    	silent_samples[mod_sample] = 1;	    program = labs(atoi(program_str));	    if ((slash_pos = strchr(program_str, '/')))	    {		banks[mod_sample] = program;		program = labs(atoi(slash_pos + 1));	    }	    sample_to_program[mod_sample] = program;	    transpose[mod_sample] = trans;	    if (strchr(finetune_str, '!'))		fine_tune[mod_sample] = 0;	    else		fine_tune[mod_sample] = atof(finetune_str) * pb_per_note;	    vol_amp[mod_sample] = amp;	    if (strchr(program_str, '*'))		is_drum_sample[mod_sample] = 1;	    else if ((chord_str = strchr(program_str, 'M')))	    {		chord_type = strchr(chord_letters, 'M') - chord_letters;		chord_subtype = atoi(chord_str + 1);		sample_chords[mod_sample] = chord_type * 3 + chord_subtype;	    }	    else if ((chord_str = strchr(program_str, 'm')))	    {		chord_type = strchr(chord_letters, 'm') - chord_letters;		chord_subtype = atoi(chord_str + 1);		sample_chords[mod_sample] = chord_type * 3 + chord_subtype;	    }	    else if ((chord_str = strchr(program_str, 'd')))	    {		chord_type = strchr(chord_letters, 'd') - chord_letters;		chord_subtype = atoi(chord_str + 1);		sample_chords[mod_sample] = chord_type * 3 + chord_subtype;	    }	    else if ((chord_str = strchr(program_str, 'f')))	    {		chord_type = strchr(chord_letters, 'f') - chord_letters;		chord_subtype = atoi(chord_str + 1);		sample_chords[mod_sample] = chord_type * 3 + chord_subtype;	    }	}	fclose(mod_cfg_file);    }    else	ctl->cmsg(CMSG_INFO, VERB_NORMAL,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -