midi.c
来自「An interactive water fountain. A realis」· C语言 代码 · 共 2,070 行 · 第 1/4 页
C
2,070 行
/*Copyright (C) 1994-1995 Apogee Software, Ltd.This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of 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 ofMERCHANTABILITY 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 Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.Modifications for JonoF's port by Jonathon Fowler (jonof@edgenetwk.com)*//********************************************************************** module: MIDI.C author: James R. Dose date: May 25, 1994 Midi song file playback routines. (c) Copyright 1994 James R. Dose. All Rights Reserved.**********************************************************************/#include <stdlib.h>#include <string.h>#include "standard.h"#include "music.h"#include "_midi.h"#include "midi.h"#include "mpu401.h"#include "compat.h"#define WIN32_LEAN_AND_MEAN#include <windows.h>extern int32_t MUSIC_SoundDevice;static const int32_t _MIDI_CommandLengths[ NUM_MIDI_CHANNELS ] ={ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0};static int32_t(*_MIDI_RerouteFunctions[ NUM_MIDI_CHANNELS ])( int32_t event, int32_t c1, int32_t c2) ={ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};static track *_MIDI_TrackPtr = NULL;static int32_t _MIDI_TrackMemSize;static int32_t _MIDI_NumTracks;static int32_t _MIDI_SongActive = FALSE;static int32_t _MIDI_SongLoaded = FALSE;static int32_t _MIDI_Loop = FALSE;static int32_t _MIDI_Division;static int32_t _MIDI_Tick = 0;static int32_t _MIDI_Beat = 1;static int32_t _MIDI_Measure = 1;static unsigned _MIDI_Time;static int32_t _MIDI_BeatsPerMeasure;static int32_t _MIDI_TicksPerBeat;static int32_t _MIDI_TimeBase;static int32_t _MIDI_FPSecondsPerTick;static unsigned _MIDI_TotalTime;static int32_t _MIDI_TotalTicks;static int32_t _MIDI_TotalBeats;static int32_t _MIDI_TotalMeasures;uint32_t _MIDI_PositionInTicks;uint32_t _MIDI_GlobalPositionInTicks;static int32_t _MIDI_Context;static int32_t _MIDI_ActiveTracks;static int32_t _MIDI_TotalVolume = MIDI_MaxVolume;static int32_t _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ];static int32_t _MIDI_UserChannelVolume[ NUM_MIDI_CHANNELS ] ={ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256};static midifuncs *_MIDI_Funcs = NULL;static int32_t Reset = FALSE;int32_t MIDI_Tempo = 120;char MIDI_PatchMap[ 128 ];/********************************************************************** Memory locked functions:**********************************************************************//*--------------------------------------------------------------------- Function: _MIDI_ReadNumber Reads a variable length number from a MIDI track.---------------------------------------------------------------------*/static int32_t _MIDI_ReadNumber( void *from, size_t size){ char *FromPtr; int32_t value; if (size > 4) { size = 4; } FromPtr = (char *)from; value = 0; while (size--) { value <<= 8; value += *FromPtr++; } return(value);}/*--------------------------------------------------------------------- Function: _MIDI_ReadDelta Reads a variable length encoded delta delay time from the MIDI data.---------------------------------------------------------------------*/static int32_t _MIDI_ReadDelta( track *ptr){ int32_t value; char c; GET_NEXT_EVENT(ptr, value); if (value & 0x80) { value &= 0x7f; do { GET_NEXT_EVENT(ptr, c); value = (value << 7) + (c & 0x7f); } while (c & 0x80); } return(value);}/*--------------------------------------------------------------------- Function: _MIDI_ResetTracks Sets the track pointers to the beginning of the song.---------------------------------------------------------------------*/static void _MIDI_ResetTracks( void){ int32_t i; track *ptr; _MIDI_Tick = 0; _MIDI_Beat = 1; _MIDI_Measure = 1; _MIDI_Time = 0; _MIDI_BeatsPerMeasure = 4; _MIDI_TicksPerBeat = _MIDI_Division; _MIDI_TimeBase = 4; _MIDI_PositionInTicks = 0; //_MIDI_GlobalPositionInTicks = 0; _MIDI_ActiveTracks = 0; _MIDI_Context = 0; ptr = _MIDI_TrackPtr; for (i = 0; i < _MIDI_NumTracks; i++) { ptr->pos = ptr->start; ptr->delay = _MIDI_ReadDelta(ptr); ptr->active = ptr->EMIDI_IncludeTrack; ptr->RunningStatus = 0; ptr->currentcontext = 0; ptr->context[ 0 ].loopstart = ptr->start; ptr->context[ 0 ].loopcount = 0; if (ptr->active) { _MIDI_ActiveTracks++; } ptr++; }}/*--------------------------------------------------------------------- Function: _MIDI_AdvanceTick Increment tick counters.---------------------------------------------------------------------*/static void _MIDI_AdvanceTick( void){ _MIDI_PositionInTicks++; _MIDI_Time += _MIDI_FPSecondsPerTick; _MIDI_Tick++; while (_MIDI_Tick > _MIDI_TicksPerBeat) { _MIDI_Tick -= _MIDI_TicksPerBeat; _MIDI_Beat++; } while (_MIDI_Beat > _MIDI_BeatsPerMeasure) { _MIDI_Beat -= _MIDI_BeatsPerMeasure; _MIDI_Measure++; }}/*--------------------------------------------------------------------- Function: _MIDI_SysEx Interpret SysEx Event.---------------------------------------------------------------------*/static void _MIDI_SysEx( track *Track){ int32_t length; length = _MIDI_ReadDelta(Track); Track->pos += length;}/*--------------------------------------------------------------------- Function: _MIDI_MetaEvent Interpret Meta Event.---------------------------------------------------------------------*/static void _MIDI_MetaEvent( track *Track){ int32_t command; int32_t length; int32_t denominator; int32_t tempo; GET_NEXT_EVENT(Track, command); GET_NEXT_EVENT(Track, length); switch (command) { case MIDI_END_OF_TRACK : Track->active = FALSE; _MIDI_ActiveTracks--; break; case MIDI_TEMPO_CHANGE : tempo = 60000000L / _MIDI_ReadNumber(Track->pos, 3); MIDI_SetTempo(tempo); break; case MIDI_TIME_SIGNATURE : if ((_MIDI_Tick > 0) || (_MIDI_Beat > 1)) { _MIDI_Measure++; } _MIDI_Tick = 0; _MIDI_Beat = 1; _MIDI_BeatsPerMeasure = (int32_t)*Track->pos; denominator = (int32_t)*(Track->pos + 1); _MIDI_TimeBase = 1; while (denominator > 0) { _MIDI_TimeBase += _MIDI_TimeBase; denominator--; } _MIDI_TicksPerBeat = (_MIDI_Division * 4) / _MIDI_TimeBase; break; } Track->pos += length;}/*--------------------------------------------------------------------- Function: _MIDI_InterpretControllerInfo Interprets the MIDI controller info.---------------------------------------------------------------------*/static int32_t _MIDI_InterpretControllerInfo( track *Track, int32_t TimeSet, int32_t channel, int32_t c1, int32_t c2){ track *trackptr; int32_t tracknum; int32_t loopcount; switch (c1) { case MIDI_MONO_MODE_ON : Track->pos++; break; case MIDI_VOLUME : if (!Track->EMIDI_VolumeChange) { _MIDI_SetChannelVolume(channel, c2); } break; case EMIDI_INCLUDE_TRACK : case EMIDI_EXCLUDE_TRACK : break; case EMIDI_PROGRAM_CHANGE : if (Track->EMIDI_ProgramChange) { _MIDI_Funcs->ProgramChange(channel, MIDI_PatchMap[ c2 & 0x7f ]); } break; case EMIDI_VOLUME_CHANGE : if (Track->EMIDI_VolumeChange) { _MIDI_SetChannelVolume(channel, c2); } break; case EMIDI_CONTEXT_START : break; case EMIDI_CONTEXT_END : if ((Track->currentcontext == _MIDI_Context) || (_MIDI_Context < 0) || (Track->context[ _MIDI_Context ].pos == NULL)) { break; } Track->currentcontext = _MIDI_Context; Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart; Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount; Track->pos = Track->context[ _MIDI_Context ].pos; Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus; if (TimeSet) { break; } _MIDI_Time = Track->context[ _MIDI_Context ].time; _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick; _MIDI_Tick = Track->context[ _MIDI_Context ].tick; _MIDI_Beat = Track->context[ _MIDI_Context ].beat; _MIDI_Measure = Track->context[ _MIDI_Context ].measure; _MIDI_BeatsPerMeasure = Track->context[ _MIDI_Context ].BeatsPerMeasure; _MIDI_TicksPerBeat = Track->context[ _MIDI_Context ].TicksPerBeat; _MIDI_TimeBase = Track->context[ _MIDI_Context ].TimeBase; TimeSet = TRUE; break; case EMIDI_LOOP_START : case EMIDI_SONG_LOOP_START : if (c2 == 0) { loopcount = EMIDI_INFINITE; } else { loopcount = c2; } if (c1 == EMIDI_SONG_LOOP_START) { trackptr = _MIDI_TrackPtr; tracknum = _MIDI_NumTracks; } else { trackptr = Track; tracknum = 1; } while (tracknum > 0) { trackptr->context[ 0 ].loopcount = loopcount; trackptr->context[ 0 ].pos = trackptr->pos; trackptr->context[ 0 ].loopstart = trackptr->pos; trackptr->context[ 0 ].RunningStatus = trackptr->RunningStatus; trackptr->context[ 0 ].active = trackptr->active; trackptr->context[ 0 ].delay = trackptr->delay; trackptr->context[ 0 ].time = _MIDI_Time; trackptr->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick; trackptr->context[ 0 ].tick = _MIDI_Tick; trackptr->context[ 0 ].beat = _MIDI_Beat; trackptr->context[ 0 ].measure = _MIDI_Measure; trackptr->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure; trackptr->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat; trackptr->context[ 0 ].TimeBase = _MIDI_TimeBase; trackptr++; tracknum--; } break; case EMIDI_LOOP_END : case EMIDI_SONG_LOOP_END : if ((c2 != EMIDI_END_LOOP_VALUE) || (Track->context[ 0 ].loopstart == NULL) || (Track->context[ 0 ].loopcount == 0)) { break; } if (c1 == EMIDI_SONG_LOOP_END) { trackptr = _MIDI_TrackPtr; tracknum = _MIDI_NumTracks; _MIDI_ActiveTracks = 0; } else { trackptr = Track; tracknum = 1; _MIDI_ActiveTracks--; } while (tracknum > 0) { if (trackptr->context[ 0 ].loopcount != EMIDI_INFINITE) { trackptr->context[ 0 ].loopcount--; } trackptr->pos = trackptr->context[ 0 ].loopstart; trackptr->RunningStatus = trackptr->context[ 0 ].RunningStatus; trackptr->delay = trackptr->context[ 0 ].delay; trackptr->active = trackptr->context[ 0 ].active; if (trackptr->active) { _MIDI_ActiveTracks++; } if (!TimeSet) { _MIDI_Time = trackptr->context[ 0 ].time; _MIDI_FPSecondsPerTick = trackptr->context[ 0 ].FPSecondsPerTick; _MIDI_Tick = trackptr->context[ 0 ].tick; _MIDI_Beat = trackptr->context[ 0 ].beat; _MIDI_Measure = trackptr->context[ 0 ].measure; _MIDI_BeatsPerMeasure = trackptr->context[ 0 ].BeatsPerMeasure; _MIDI_TicksPerBeat = trackptr->context[ 0 ].TicksPerBeat; _MIDI_TimeBase = trackptr->context[ 0 ].TimeBase; TimeSet = TRUE; } trackptr++; tracknum--; } break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?