📄 native_midi_mac.c
字号:
/* native_midi_mac: Native Midi support on MacOS for the SDL_mixer library Copyright (C) 2001 Max Horn This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Max Horn max@quendi.de*/#include "SDL_config.h"#include "SDL_endian.h"#if __MACOS__ || __MACOSX__#include "native_midi.h"#include "native_midi_common.h"#if __MACOSX__#include <QuickTime/QuickTimeMusic.h>#else#include <QuickTimeMusic.h>#endif#include <assert.h>#include <stdlib.h>#include <string.h>/* Native Midi song */struct _NativeMidiSong{ Uint32 *tuneSequence; Uint32 *tuneHeader;};enum{ /* number of (32-bit) long words in a note request event */ kNoteRequestEventLength = ((sizeof(NoteRequest)/sizeof(long)) + 2), /* number of (32-bit) long words in a marker event */ kMarkerEventLength = 1, /* number of (32-bit) long words in a general event, minus its data */ kGeneralEventLength = 2};#define ERROR_BUF_SIZE 256#define BUFFER_INCREMENT 5000#define REST_IF_NECESSARY() do {\ int timeDiff = eventPos->time - lastEventTime; \ if(timeDiff) \ { \ timeDiff = (int)(timeDiff*tick); \ qtma_StuffRestEvent(*tunePos, timeDiff); \ tunePos++; \ lastEventTime = eventPos->time; \ } \ } while(0)static Uint32 *BuildTuneSequence(MIDIEvent *evntlist, int ppqn, int part_poly_max[32], int part_to_inst[32], int *numParts);static Uint32 *BuildTuneHeader(int part_poly_max[32], int part_to_inst[32], int numParts);/* The global TunePlayer instance */static TunePlayer gTunePlayer = NULL;static int gInstaceCount = 0;static Uint32 *gCurrentTuneSequence = NULL;static char gErrorBuffer[ERROR_BUF_SIZE] = "";/* Check whether QuickTime is available */int native_midi_detect(){ /* TODO */ return 1;}NativeMidiSong *native_midi_loadsong(char *midifile){ NativeMidiSong *song = NULL; MIDIEvent *evntlist = NULL; int part_to_inst[32]; int part_poly_max[32]; int numParts = 0; Uint16 ppqn; SDL_RWops *rw; /* Init the arrays */ memset(part_poly_max,0,sizeof(part_poly_max)); memset(part_to_inst,-1,sizeof(part_to_inst)); /* Attempt to load the midi file */ rw = SDL_RWFromFile(midifile, "rb"); if (rw) { evntlist = CreateMIDIEventList(rw, &ppqn); SDL_RWclose(rw); if (!evntlist) goto bail; } /* Allocate memory for the song struct */ song = malloc(sizeof(NativeMidiSong)); if (!song) goto bail; /* Build a tune sequence from the event list */ song->tuneSequence = BuildTuneSequence(evntlist, ppqn, part_poly_max, part_to_inst, &numParts); if(!song->tuneSequence) goto bail; /* Now build a tune header from the data we collect above, create all parts as needed and assign them the correct instrument. */ song->tuneHeader = BuildTuneHeader(part_poly_max, part_to_inst, numParts); if(!song->tuneHeader) goto bail; /* Increment the instance count */ gInstaceCount++; if (gTunePlayer == NULL) gTunePlayer = OpenDefaultComponent(kTunePlayerComponentType, 0); /* Finally, free the event list */ FreeMIDIEventList(evntlist); return song; bail: if (evntlist) FreeMIDIEventList(evntlist); if (song) { if(song->tuneSequence) free(song->tuneSequence); if(song->tuneHeader) DisposePtr((Ptr)song->tuneHeader); free(song); } return NULL;}NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw){ NativeMidiSong *song = NULL; MIDIEvent *evntlist = NULL; int part_to_inst[32]; int part_poly_max[32]; int numParts = 0; Uint16 ppqn; /* Init the arrays */ memset(part_poly_max,0,sizeof(part_poly_max)); memset(part_to_inst,-1,sizeof(part_to_inst)); /* Attempt to load the midi file */ evntlist = CreateMIDIEventList(rw, &ppqn); if (!evntlist) goto bail; /* Allocate memory for the song struct */ song = malloc(sizeof(NativeMidiSong)); if (!song) goto bail; /* Build a tune sequence from the event list */ song->tuneSequence = BuildTuneSequence(evntlist, ppqn, part_poly_max, part_to_inst, &numParts); if(!song->tuneSequence) goto bail; /* Now build a tune header from the data we collect above, create all parts as needed and assign them the correct instrument. */ song->tuneHeader = BuildTuneHeader(part_poly_max, part_to_inst, numParts); if(!song->tuneHeader) goto bail; /* Increment the instance count */ gInstaceCount++; if (gTunePlayer == NULL) gTunePlayer = OpenDefaultComponent(kTunePlayerComponentType, 0); /* Finally, free the event list */ FreeMIDIEventList(evntlist); return song; bail: if (evntlist) FreeMIDIEventList(evntlist); if (song) { if(song->tuneSequence) free(song->tuneSequence); if(song->tuneHeader) DisposePtr((Ptr)song->tuneHeader); free(song); } return NULL;}void native_midi_freesong(NativeMidiSong *song){ if(!song || !song->tuneSequence) return; /* If this is the currently playing song, stop it now */ if (song->tuneSequence == gCurrentTuneSequence) native_midi_stop(); /* Finally, free the data storage */ free(song->tuneSequence); DisposePtr((Ptr)song->tuneHeader); free(song); /* Increment the instance count */ gInstaceCount--; if ((gTunePlayer != NULL) && (gInstaceCount == 0)) { CloseComponent(gTunePlayer); gTunePlayer = NULL; }}void native_midi_start(NativeMidiSong *song){ UInt32 queueFlags = 0; ComponentResult tpError; assert (gTunePlayer != NULL); SDL_PauseAudio(1); SDL_UnlockAudio(); /* First, stop the currently playing music */ native_midi_stop(); /* Set up the queue flags */ queueFlags = kTuneStartNow; /* Set the time scale (units per second), we want milliseconds */ tpError = TuneSetTimeScale(gTunePlayer, 1000); if (tpError != noErr) { strncpy (gErrorBuffer, "MIDI error during TuneSetTimeScale", ERROR_BUF_SIZE); goto done; } /* Set the header, to tell what instruments are used */ tpError = TuneSetHeader(gTunePlayer, (UInt32 *)song->tuneHeader); if (tpError != noErr) { strncpy (gErrorBuffer, "MIDI error during TuneSetHeader", ERROR_BUF_SIZE); goto done; } /* Have it allocate whatever resources are needed */ tpError = TunePreroll(gTunePlayer); if (tpError != noErr) { strncpy (gErrorBuffer, "MIDI error during TunePreroll", ERROR_BUF_SIZE); goto done; } /* We want to play at normal volume */ tpError = TuneSetVolume(gTunePlayer, 0x00010000); if (tpError != noErr) { strncpy (gErrorBuffer, "MIDI error during TuneSetVolume", ERROR_BUF_SIZE); goto done; } /* Finally, start playing the full song */ gCurrentTuneSequence = song->tuneSequence; tpError = TuneQueue(gTunePlayer, (UInt32 *)song->tuneSequence, 0x00010000, 0, 0xFFFFFFFF, queueFlags, NULL, 0); if (tpError != noErr) { strncpy (gErrorBuffer, "MIDI error during TuneQueue", ERROR_BUF_SIZE); goto done; } done: SDL_LockAudio(); SDL_PauseAudio(0);}void native_midi_stop(){ if (gTunePlayer == NULL) return; /* Stop music */ TuneStop(gTunePlayer, 0); /* Deallocate all instruments */ TuneUnroll(gTunePlayer);}int native_midi_active(){ if (gTunePlayer != NULL) { TuneStatus ts; TuneGetStatus(gTunePlayer,&ts); return ts.queueTime != 0; } else return 0;}void native_midi_setvolume(int volume){ if (gTunePlayer == NULL) return; /* QTMA olume may range from 0.0 to 1.0 (in 16.16 fixed point encoding) */ TuneSetVolume(gTunePlayer, (0x00010000 * volume)/SDL_MIX_MAXVOLUME);}char *native_midi_error(){ return gErrorBuffer;}Uint32 *BuildTuneSequence(MIDIEvent *evntlist, int ppqn, int part_poly_max[32], int part_to_inst[32], int *numParts){ int part_poly[32]; int channel_to_part[16]; int channel_pan[16]; int channel_vol[16];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -