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 + -
显示快捷键?