midi.c
来自「An interactive water fountain. A realis」· C语言 代码 · 共 2,070 行 · 第 1/4 页
C
2,070 行
_MIDI_Context = context; }}/*--------------------------------------------------------------------- Function: MIDI_GetContext Returns the current song context.---------------------------------------------------------------------*/int32_t MIDI_GetContext( void){ return _MIDI_Context;}/*--------------------------------------------------------------------- Function: MIDI_SetLoopFlag Sets whether the song should loop when finished or not.---------------------------------------------------------------------*/void MIDI_SetLoopFlag( int32_t loopflag){ _MIDI_Loop = loopflag;}/*--------------------------------------------------------------------- Function: MIDI_ContinueSong Continues playback of a paused song.---------------------------------------------------------------------*/void MIDI_ContinueSong( void){ if (_MIDI_SongLoaded) { _MIDI_SongActive = TRUE; MPU_Unpause(); }}/*--------------------------------------------------------------------- Function: MIDI_PauseSong Pauses playback of the current song.---------------------------------------------------------------------*/void MIDI_PauseSong( void){ if (_MIDI_SongLoaded) { _MIDI_SongActive = FALSE; MIDI_AllNotesOff(); MPU_Pause(); }}/*--------------------------------------------------------------------- Function: MIDI_SongPlaying Returns whether a song is playing or not.---------------------------------------------------------------------*/int32_t MIDI_SongPlaying( void){ return(_MIDI_SongActive);}/*--------------------------------------------------------------------- Function: MIDI_SetMidiFuncs Selects the routines that send the MIDI data to the music device.---------------------------------------------------------------------*/void MIDI_SetMidiFuncs( midifuncs *funcs){ _MIDI_Funcs = funcs;}/*--------------------------------------------------------------------- Function: MIDI_StopSong Stops playback of the currently playing song.---------------------------------------------------------------------*/void MIDI_StopSong( void){ if (_MIDI_SongLoaded) { _MIDI_SongActive = FALSE; _MIDI_SongLoaded = FALSE; MIDI_Reset(); _MIDI_ResetTracks(); if (_MIDI_Funcs->ReleasePatches) { _MIDI_Funcs->ReleasePatches(); } Bfree(_MIDI_TrackPtr); _MIDI_TrackPtr = NULL; _MIDI_NumTracks = 0; _MIDI_TrackMemSize = 0; _MIDI_TotalTime = 0; _MIDI_TotalTicks = 0; _MIDI_TotalBeats = 0; _MIDI_TotalMeasures = 0; MPU_Reset(); }}/*--------------------------------------------------------------------- Function: MIDI_PlaySong Begins playback of a MIDI song.---------------------------------------------------------------------*/int32_t MIDI_PlaySong( char *song, int32_t loopflag){ int32_t numtracks; int32_t format; int32_t headersize; int32_t tracklength; track *CurrentTrack; char *ptr; if (_MIDI_SongLoaded) { MIDI_StopSong(); } MPU_Init(MUSIC_SoundDevice); _MIDI_Loop = loopflag; if (_MIDI_Funcs == NULL) { return(MIDI_NullMidiModule); } if (*(uint32_t *)song != MIDI_HEADER_SIGNATURE) { return(MIDI_InvalidMidiFile); } song += 4; headersize = _MIDI_ReadNumber(song, 4); song += 4; format = _MIDI_ReadNumber(song, 2); _MIDI_NumTracks = _MIDI_ReadNumber(song + 2, 2); _MIDI_Division = _MIDI_ReadNumber(song + 4, 2); if (_MIDI_Division < 0) { // If a SMPTE time division is given, just set to 96 so no errors occur _MIDI_Division = 96; } if (format > MAX_FORMAT) { return(MIDI_UnknownMidiFormat); } ptr = song + headersize; if (_MIDI_NumTracks == 0) { return(MIDI_NoTracks); } _MIDI_TrackMemSize = _MIDI_NumTracks * sizeof(track); _MIDI_TrackPtr = Bmalloc(_MIDI_TrackMemSize); if (_MIDI_TrackPtr == NULL) { return(MIDI_NoMemory); } CurrentTrack = _MIDI_TrackPtr; numtracks = _MIDI_NumTracks; while (numtracks--) { if (*(uint32_t *)ptr != MIDI_TRACK_SIGNATURE) { Bfree(_MIDI_TrackPtr); _MIDI_TrackPtr = NULL; _MIDI_TrackMemSize = 0; return(MIDI_InvalidTrack); } tracklength = _MIDI_ReadNumber(ptr + 4, 4); ptr += 8; CurrentTrack->start = ptr; ptr += tracklength; CurrentTrack++; } if (_MIDI_Funcs->GetVolume != NULL) { _MIDI_TotalVolume = _MIDI_Funcs->GetVolume(); } _MIDI_InitEMIDI(); if (_MIDI_Funcs->LoadPatch) { MIDI_LoadTimbres(); } _MIDI_ResetTracks(); if (!Reset) { MIDI_Reset(); } Reset = FALSE; MIDI_SetDivision(_MIDI_Division); //MIDI_SetTempo( 120 ); _MIDI_SongLoaded = TRUE; _MIDI_SongActive = TRUE; while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine(); MPU_BeginPlayback(); return(MIDI_Ok);}/*--------------------------------------------------------------------- Function: MIDI_SetTempo Sets the song tempo.---------------------------------------------------------------------*/void MIDI_SetTempo( int32_t tempo){ int32_t tickspersecond; MIDI_Tempo = tempo; tickspersecond = ((tempo) * _MIDI_Division) / 60; _MIDI_FPSecondsPerTick = (1 << TIME_PRECISION) / tickspersecond; MPU_SetTempo(tempo);}void MIDI_SetDivision(int32_t division){ MPU_SetDivision(division);}/*--------------------------------------------------------------------- Function: MIDI_GetTempo Returns the song tempo.---------------------------------------------------------------------*/int32_t MIDI_GetTempo( void){ return(MIDI_Tempo);}/*--------------------------------------------------------------------- Function: _MIDI_ProcessNextTick Sets the position of the song pointer.---------------------------------------------------------------------*/static int32_t _MIDI_ProcessNextTick( void){ int32_t event; int32_t channel; int32_t command; track *Track; int32_t tracknum; int32_t status; int32_t c1 = 0; int32_t c2 = 0; int32_t TimeSet = FALSE; Track = _MIDI_TrackPtr; tracknum = 0; while ((tracknum < _MIDI_NumTracks) && (Track != NULL)) { while ((Track->active) && (Track->delay == 0)) { GET_NEXT_EVENT(Track, event); if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL) { switch (event) { case MIDI_SYSEX : case MIDI_SYSEX_CONTINUE : _MIDI_SysEx(Track); break; case MIDI_META_EVENT : _MIDI_MetaEvent(Track); break; } if (Track->active) { Track->delay = _MIDI_ReadDelta(Track); } continue; } if (event & MIDI_RUNNING_STATUS) { Track->RunningStatus = event; } else { event = Track->RunningStatus; Track->pos--; } channel = GET_MIDI_CHANNEL(event); command = GET_MIDI_COMMAND(event); if (_MIDI_CommandLengths[ command ] > 0) { GET_NEXT_EVENT(Track, c1); if (_MIDI_CommandLengths[ command ] > 1) { GET_NEXT_EVENT(Track, c2); } } if (_MIDI_RerouteFunctions[ channel ] != NULL) { status = _MIDI_RerouteFunctions[ channel ](event, c1, c2); if (status == MIDI_DONT_PLAY) { Track->delay = _MIDI_ReadDelta(Track); continue; } } switch (command) { case MIDI_NOTE_OFF : break; case MIDI_NOTE_ON : break; case MIDI_POLY_AFTER_TCH : if (_MIDI_Funcs->PolyAftertouch) { _MIDI_Funcs->PolyAftertouch(channel, c1, c2); } break; case MIDI_CONTROL_CHANGE : TimeSet = _MIDI_InterpretControllerInfo(Track, TimeSet, channel, c1, c2); break; case MIDI_PROGRAM_CHANGE : if ((_MIDI_Funcs->ProgramChange) && (!Track->EMIDI_ProgramChange)) { _MIDI_Funcs->ProgramChange(channel, c1); } break; case MIDI_AFTER_TOUCH : if (_MIDI_Funcs->ChannelAftertouch) { _MIDI_Funcs->ChannelAftertouch(channel, c1); } break; case MIDI_PITCH_BEND : if (_MIDI_Funcs->PitchBend) { _MIDI_Funcs->PitchBend(channel, c1, c2); } break; default : break; } Track->delay = _MIDI_ReadDelta(Track); } Track->delay--; Track++; tracknum++; if (_MIDI_ActiveTracks == 0) { break; } } _MIDI_AdvanceTick(); return(TimeSet);}/*--------------------------------------------------------------------- Function: MIDI_SetSongTick Sets the position of the song pointer.---------------------------------------------------------------------*/void MIDI_SetSongTick( uint32_t PositionInTicks){ if (!_MIDI_SongLoaded) { return; } MIDI_PauseSong(); if (PositionInTicks < _MIDI_PositionInTicks) { _MIDI_ResetTracks(); MIDI_Reset(); } while (_MIDI_PositionInTicks < PositionInTicks) { if (_MIDI_ProcessNextTick()) { break; } if (_MIDI_ActiveTracks == 0) { _MIDI_ResetTracks(); if (!_MIDI_Loop) { return; } break; } } MIDI_SetVolume(_MIDI_TotalVolume); MIDI_ContinueSong();}/*--------------------------------------------------------------------- Function: MIDI_SetSongTime
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?