Browse Source

iOS native_midi reimplemented with AVMIDIPlayer for better quality; use OSX built-in GS waveform

Pal Lockheart 7 years ago
parent
commit
48d0e7e187

+ 8 - 4
ios/SDLPal/SDLPal.xcodeproj/project.pbxproj

@@ -105,7 +105,8 @@
 		C63505731EA6570300186049 /* midi.c in Sources */ = {isa = PBXBuildFile; fileRef = C635056B1EA6570300186049 /* midi.c */; };
 		C63505741EA6570300186049 /* private.c in Sources */ = {isa = PBXBuildFile; fileRef = C635056C1EA6570300186049 /* private.c */; };
 		C635057F1EA6578700186049 /* native_midi_common.c in Sources */ = {isa = PBXBuildFile; fileRef = C635057B1EA6578700186049 /* native_midi_common.c */; };
-		C63505801EA6578700186049 /* native_midi_ios.c in Sources */ = {isa = PBXBuildFile; fileRef = C635057D1EA6578700186049 /* native_midi_ios.c */; };
+		C63505801EA6578700186049 /* native_midi.m in Sources */ = {isa = PBXBuildFile; fileRef = C635057D1EA6578700186049 /* native_midi.m */; };
+		C694CF871EB6197C0006F937 /* gs_instruments.dls in Resources */ = {isa = PBXBuildFile; fileRef = C694CF861EB619660006F937 /* gs_instruments.dls */; };
 		C6E974A21E49C24500F76B17 /* libSDL2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C6E9749D1E49C22D00F76B17 /* libSDL2.a */; };
 /* End PBXBuildFile section */
 
@@ -352,7 +353,8 @@
 		C635057A1EA6578700186049 /* native_midi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = native_midi.h; sourceTree = "<group>"; };
 		C635057B1EA6578700186049 /* native_midi_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = native_midi_common.c; sourceTree = "<group>"; };
 		C635057C1EA6578700186049 /* native_midi_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = native_midi_common.h; sourceTree = "<group>"; };
-		C635057D1EA6578700186049 /* native_midi_ios.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = native_midi_ios.c; path = ../iOS/SDLPal/SDLPal/native_midi_ios.c; sourceTree = "<group>"; };
+		C635057D1EA6578700186049 /* native_midi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = native_midi.m; path = ../iOS/SDLPal/SDLPal/native_midi.m; sourceTree = "<group>"; };
+		C694CF861EB619660006F937 /* gs_instruments.dls */ = {isa = PBXFileReference; lastKnownFileType = file; name = gs_instruments.dls; path = /System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -745,7 +747,8 @@
 				C635057A1EA6578700186049 /* native_midi.h */,
 				C635057B1EA6578700186049 /* native_midi_common.c */,
 				C635057C1EA6578700186049 /* native_midi_common.h */,
-				C635057D1EA6578700186049 /* native_midi_ios.c */,
+				C635057D1EA6578700186049 /* native_midi.m */,
+				C694CF861EB619660006F937 /* gs_instruments.dls */,
 			);
 			name = native_midi;
 			path = ../../native_midi;
@@ -840,6 +843,7 @@
 				71655075195BB372006E1227 /* Default@2x.png in Resources */,
 				71655077195BB372006E1227 /* Default-568h@2x.png in Resources */,
 				7165507F195BB3D8006E1227 /* Icon.png in Resources */,
+				C694CF871EB6197C0006F937 /* gs_instruments.dls in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -900,7 +904,7 @@
 				C63505731EA6570300186049 /* midi.c in Sources */,
 				57FB01481B7A50B0005FCF4C /* floor0.c in Sources */,
 				7165526F195BB6DB006E1227 /* fixed.c in Sources */,
-				C63505801EA6578700186049 /* native_midi_ios.c in Sources */,
+				C63505801EA6578700186049 /* native_midi.m in Sources */,
 				71655270195BB6DB006E1227 /* frame.c in Sources */,
 				71655271195BB6DB006E1227 /* huffman.c in Sources */,
 				71655273195BB6DB006E1227 /* layer12.c in Sources */,

+ 143 - 0
ios/SDLPal/SDLPal/native_midi.m

@@ -0,0 +1,143 @@
+/*
+ native_midi_android:  Native Midi support on iOS for SDLPal
+ Copyright (C) 2017  Pal Lockheart
+ 
+ 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
+ 
+ Pal Lockheart
+ */
+
+#include "SDL_config.h"
+
+#include "SDL.h"
+#include "SDL_endian.h"
+#include "native_midi/native_midi.h"
+
+#import <Foundation/Foundation.h>
+#import <AVFoundation/AVFoundation.h>
+
+#include "palcommon.h"
+#include "util.h"
+
+/* Native Midi song */
+struct _NativeMidiSong
+{
+    int _placeholder;
+    int playing;
+};
+
+static NativeMidiSong *currentsong = NULL;
+static int latched_volume = 128;
+
+static AVMIDIPlayer *midiPlayer;
+
+int native_midi_detect()
+{
+    return 1;  /* always available. */
+}
+
+
+NativeMidiSong *native_midi_loadsong(const char *midifile)
+{
+    NativeMidiSong *retval = NULL;
+    SDL_RWops *rw = SDL_RWFromFile(midifile, "rb");
+    if (rw != NULL) {
+        retval = native_midi_loadsong_RW(rw);
+        SDL_RWclose(rw);
+    }
+    
+    return retval;
+}
+
+NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
+{
+    NativeMidiSong *retval = (NativeMidiSong *)malloc(sizeof(NativeMidiSong));
+    char midiInterFile[PATH_MAX];
+    snprintf(midiInterFile, PATH_MAX, "%s%s", [NSTemporaryDirectory() UTF8String], "inter.mid");
+    FILE *fp = fopen(midiInterFile, "wb+");
+    if (fp)
+    {
+        char buf[4096];
+        size_t bytes;
+        while((bytes = SDL_RWread(rw, buf, sizeof(char), sizeof(buf)))!=0)
+            fwrite(buf, sizeof(char), bytes, fp);
+        fclose(fp);
+        
+        memset(retval, 0, sizeof(NativeMidiSong));
+        NSURL *midiFileURL = [NSURL URLWithString:[NSString stringWithUTF8String:midiInterFile]];
+        NSURL *bankURL = [[NSBundle mainBundle] URLForResource:@"gs_instruments" withExtension: @"dls"];
+        if( midiPlayer ) {
+            [midiPlayer dealloc];
+            midiPlayer = nil;
+        }
+        NSError *err=nil;
+        midiPlayer = [[AVMIDIPlayer new] initWithContentsOfURL:midiFileURL soundBankURL:bankURL error:&err];
+        [midiPlayer prepareToPlay];
+    }
+    return retval;
+}
+
+void native_midi_freesong(NativeMidiSong *song)
+{
+    if (song != NULL)
+    {
+        native_midi_stop();
+        if (currentsong == song)
+            currentsong = NULL;
+        free(song);
+        if( midiPlayer ) {
+            [midiPlayer dealloc];
+            midiPlayer = nil;
+        }
+    }
+}
+
+void native_midi_start(NativeMidiSong *song)
+{
+    native_midi_stop();
+    if (song != NULL)
+    {
+        currentsong = song;
+        currentsong->playing = 1;
+        [midiPlayer play:^(){
+            if( currentsong ) {
+                midiPlayer.currentPosition = 0;
+                native_midi_start(currentsong);
+            }
+        }];
+    }
+}
+
+void native_midi_stop()
+{
+    if (currentsong) {
+        currentsong->playing = 0;
+        [midiPlayer stop];
+    }
+}
+
+int native_midi_active()
+{
+    return currentsong ? currentsong->playing : 0;
+}
+
+void native_midi_setvolume(int volume)
+{
+}
+
+const char *native_midi_error(void)
+{
+    return "";  /* !!! FIXME */
+}

+ 0 - 316
ios/SDLPal/SDLPal/native_midi_ios.c

@@ -1,316 +0,0 @@
-/*  
-    native_midi_macosx:  Native Midi support on Mac OS X for the SDL_mixer library
-    Copyright (C) 2009  Ryan C. Gordon
-
-    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
-
-    Ryan C. Gordon
-    icculus@icculus.org
-*/
-
-#ifdef __APPLE__
-
-/* This is Mac OS X only, using Core MIDI.
-   Mac OS 9 support via QuickTime is in native_midi_mac.c */
-
-#include "SDL_config.h"
-
-#include <AudioToolbox/AudioToolbox.h>
-#include <AvailabilityMacros.h>
-
-#include "SDL.h"
-#include "SDL_endian.h"
-#include "native_midi.h"
-
-/* Native Midi song */
-struct _NativeMidiSong
-{
-    MusicPlayer player;
-    MusicSequence sequence;
-    MusicTimeStamp endTime;
-    AudioUnit audiounit;
-};
-
-static NativeMidiSong *currentsong = NULL;
-static int latched_volume = 128;
-
-static OSStatus
-GetSequenceLength(MusicSequence sequence, MusicTimeStamp *_sequenceLength)
-{
-    // http://lists.apple.com/archives/Coreaudio-api/2003/Jul/msg00370.html
-    // figure out sequence length
-    UInt32 ntracks, i;
-    MusicTimeStamp sequenceLength = 0;
-    OSStatus err;
-
-    err = MusicSequenceGetTrackCount(sequence, &ntracks);
-    if (err != noErr)
-        return err;
-
-    for (i = 0; i < ntracks; ++i)
-    {
-        MusicTrack track;
-        MusicTimeStamp tracklen = 0;
-        UInt32 tracklenlen = sizeof (tracklen);
-
-        err = MusicSequenceGetIndTrack(sequence, i, &track);
-        if (err != noErr)
-            return err;
-
-        err = MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
-                                    &tracklen, &tracklenlen);
-        if (err != noErr)
-            return err;
-
-        if (sequenceLength < tracklen)
-            sequenceLength = tracklen;
-    }
-
-    *_sequenceLength = sequenceLength;
-
-    return noErr;
-}
-
-
-/* we're looking for the sequence output audiounit. */
-static OSStatus
-GetSequenceAudioUnit(MusicSequence sequence, AudioUnit *aunit)
-{
-    AUGraph graph;
-    UInt32 nodecount, i;
-    OSStatus err;
-
-    err = MusicSequenceGetAUGraph(sequence, &graph);
-    if (err != noErr)
-        return err;
-
-    err = AUGraphGetNodeCount(graph, &nodecount);
-    if (err != noErr)
-        return err;
-
-    for (i = 0; i < nodecount; i++) {
-        AUNode node;
-
-        if (AUGraphGetIndNode(graph, i, &node) != noErr)
-            continue;  /* better luck next time. */
-
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 /* this is deprecated, but works back to 10.0 */
-        {
-            struct ComponentDescription desc;
-            UInt32 classdatasize = 0;
-            void *classdata = NULL;
-            err = AUGraphGetNodeInfo(graph, node, &desc, &classdatasize,
-                                     &classdata, aunit);
-            if (err != noErr)
-                continue;
-            else if (desc.componentType != kAudioUnitType_Output)
-                continue;
-            else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput)
-                continue;
-        }
-        #else  /* not deprecated, but requires 10.5 or later */
-        {
-            AudioComponentDescription desc;
-            if (AUGraphNodeInfo(graph, node, &desc, aunit) != noErr)
-                continue;
-            else if (desc.componentType != kAudioUnitType_Output)
-                continue;
-            else if (desc.componentSubType != kAudioUnitSubType_GenericOutput)
-                continue;
-        }
-        #endif
-
-        return noErr;  /* found it! */
-    }
-
-    return kAUGraphErr_NodeNotFound;
-}
-
-
-int native_midi_detect()
-{
-    return 1;  /* always available. */
-}
-
-NativeMidiSong *native_midi_loadsong(const char *midifile)
-{
-    NativeMidiSong *retval = NULL;
-    SDL_RWops *rw = SDL_RWFromFile(midifile, "rb");
-    if (rw != NULL) {
-        retval = native_midi_loadsong_RW(rw);
-        SDL_RWclose(rw);
-    }
-
-    return retval;
-}
-
-NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
-{
-    NativeMidiSong *retval = NULL;
-    void *buf = NULL;
-    int len = 0;
-    CFDataRef data = NULL;
-
-    if (SDL_RWseek(rw, 0, RW_SEEK_END) < 0)
-        goto fail;
-    len = SDL_RWtell(rw);
-    if (len < 0)
-        goto fail;
-    if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0)
-        goto fail;
-
-    buf = malloc(len);
-    if (buf == NULL)
-        goto fail;
-
-    if (SDL_RWread(rw, buf, len, 1) != 1)
-        goto fail;
-
-    retval = malloc(sizeof(NativeMidiSong));
-    if (retval == NULL)
-        goto fail;
-
-    memset(retval, '\0', sizeof (*retval));
-
-    if (NewMusicPlayer(&retval->player) != noErr)
-        goto fail;
-    if (NewMusicSequence(&retval->sequence) != noErr)
-        goto fail;
-
-    data = CFDataCreate(NULL, (const UInt8 *) buf, len);
-    if (data == NULL)
-        goto fail;
-
-    free(buf);
-    buf = NULL;
-
-    #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 /* this is deprecated, but works back to 10.3 */
-    if (MusicSequenceLoadSMFDataWithFlags(retval->sequence, data, 0) != noErr)
-        goto fail;
-    #else  /* not deprecated, but requires 10.5 or later */
-    if (MusicSequenceFileLoadData(retval->sequence, data, 0, 0) != noErr)
-        goto fail;
-    #endif
-
-    CFRelease(data);
-    data = NULL;
-
-    if (GetSequenceLength(retval->sequence, &retval->endTime) != noErr)
-        goto fail;
-
-    if (MusicPlayerSetSequence(retval->player, retval->sequence) != noErr)
-        goto fail;
-
-    return retval;
-
-fail:
-    if (retval) {
-        if (retval->sequence)
-            DisposeMusicSequence(retval->sequence);
-        if (retval->player)
-            DisposeMusicPlayer(retval->player);
-        free(retval);
-    }
-
-    if (data)
-        CFRelease(data);
-
-    if (buf)
-        free(buf);
-
-    return NULL;
-}
-
-void native_midi_freesong(NativeMidiSong *song)
-{
-    if (song != NULL) {
-        if (currentsong == song)
-            currentsong = NULL;
-        MusicPlayerStop(song->player);
-        DisposeMusicSequence(song->sequence);
-        DisposeMusicPlayer(song->player);
-        free(song);
-    }
-}
-
-void native_midi_start(NativeMidiSong *song)
-{
-    int vol;
-
-    if (song == NULL)
-        return;
-
-    SDL_PauseAudio(1);
-    SDL_UnlockAudio();
-
-    if (currentsong)
-        MusicPlayerStop(currentsong->player);
-
-    currentsong = song;
-    MusicPlayerStart(song->player);
-
-    GetSequenceAudioUnit(song->sequence, &song->audiounit);
-
-    vol = latched_volume;
-    latched_volume++;  /* just make this not match. */
-    native_midi_setvolume(vol);
-
-    SDL_LockAudio();
-    SDL_PauseAudio(0);
-}
-
-void native_midi_stop()
-{
-    if (currentsong) {
-        SDL_PauseAudio(1);
-        SDL_UnlockAudio();
-        MusicPlayerStop(currentsong->player);
-        currentsong = NULL;
-        SDL_LockAudio();
-        SDL_PauseAudio(0);
-    }
-}
-
-int native_midi_active()
-{
-    MusicTimeStamp currentTime = 0;
-    if (currentsong == NULL)
-        return 0;
-
-    MusicPlayerGetTime(currentsong->player, &currentTime);
-    return ((currentTime < currentsong->endTime) ||
-            (currentTime >= kMusicTimeStamp_EndOfTrack));
-}
-
-void native_midi_setvolume(int volume)
-{
-    if (latched_volume == volume)
-        return;
-
-    latched_volume = volume;
-    if ((currentsong) && (currentsong->audiounit)) {
-        const float floatvol = ((float) volume) / ((float) 128);
-        AudioUnitSetParameter(currentsong->audiounit, kHALOutputParam_Volume,
-                              kAudioUnitScope_Global, 0, floatvol, 0);
-    }
-}
-
-const char *native_midi_error(void)
-{
-    return "";  /* !!! FIXME */
-}
-
-#endif
-

+ 1 - 1
midi.c

@@ -52,7 +52,7 @@ MIDI_Play(
    if (gConfig.fIsWIN95)
    {
       char filename[1024];
-      sprintf(filename, "%s/musics/%.3d.mid", PAL_PREFIX, iNumRIX);
+      sprintf(filename, "%s/Musics/%.3d.mid", PAL_PREFIX, iNumRIX);
 
       g_pMid = native_midi_loadsong(filename);
       if (g_pMid != NULL)