Skip to content
This repository has been archived by the owner on Jul 17, 2024. It is now read-only.

Add MP3 decoding #14

Open
nornagon opened this issue Apr 29, 2011 · 5 comments
Open

Add MP3 decoding #14

nornagon opened this issue Apr 29, 2011 · 5 comments

Comments

@nornagon
Copy link

wav and caf are too big; I have about 40 sound effects I want to use. In linear pcm that comes to about 17MB.

@zoul
Copy link
Owner

zoul commented May 5, 2011

I’d like to do this, but it’s very low priority, since I don’t need it myself. Not expected to come in the upcoming months.

@nornagon
Copy link
Author

nornagon commented May 5, 2011

I needed it, so I have a patch that does it. I'll clean it up and send
a pull request.

On Fri, May 6, 2011 at 12:15 AM, zoul
reply@reply.github.com
wrote:

I’d like to do this, but it’s very low priority, since I don’t need it myself. Not expected to come in the upcoming months.

Reply to this email directly or view it on GitHub:
#14 (comment)

@pomarec
Copy link

pomarec commented Jul 28, 2011

nornagon, I would love to use it !

@nornagon
Copy link
Author

Don't have the time to clean it up and make a proper pull request right now (or even to test that the code still works) but here's the patch I made. IIRC I copied the code to load mp3s from cocos2d.

diff --git a/Source/PCMDecoder.m b/Source/PCMDecoder.m
index bd885f3..3787b54 100644
--- a/Source/PCMDecoder.m
+++ b/Source/PCMDecoder.m
@@ -1,90 +1,123 @@
 #import "PCMDecoder.h"
-#import  
+#import 
+#import 
 #import "Sample.h"
 #import "Reporter.h"
+#import 
 
 @implementation PCMDecoder
 
 + (Sample*) decodeFile: (NSURL*) fileURL error: (NSError**) error
 {
-    OSStatus errcode = noErr;
-    UInt32 propertySize;
-    AudioFileID fileId = 0;
-    Reporter *reporter = [Reporter forDomain:@"Sample Decoder" error:error];
-    
-    errcode = AudioFileOpenURL((CFURLRef) fileURL, kAudioFileReadPermission, 0, &fileId);
-    if (errcode) {
-        *error = [reporter errorWithCode:kDEFileReadError];
-        return nil;
-    }
-    
-    AudioStreamBasicDescription fileFormat;
-    propertySize = sizeof(fileFormat);
-    errcode = AudioFileGetProperty(fileId, kAudioFilePropertyDataFormat, &propertySize, &fileFormat);
-    if (errcode) {
-        *error = [reporter errorWithCode:kDEFileFormatReadError];
-        AudioFileClose(fileId);
-        return nil;
-    }
-
-    if (fileFormat.mFormatID != kAudioFormatLinearPCM) { 
-        *error = [reporter
-            errorWithCode:kDEInvalidFileFormat
-            description:@"Sound file not linear PCM."];
-        AudioFileClose(fileId);
-        return nil;
-    }
-    
-    UInt64 fileSize = 0;
-    propertySize = sizeof(fileSize);
-    errcode = AudioFileGetProperty(fileId, kAudioFilePropertyAudioDataByteCount, &propertySize, &fileSize);
-    if (errcode) {
-        *error = [reporter
-            errorWithCode:kDEFileFormatReadError
-            description:@"Failed to read sound file size."];
-        AudioFileClose(fileId);
-        return nil;
-    }
-
-    double sampleLength = -1;
-    propertySize = sizeof(sampleLength);
-    errcode = AudioFileGetProperty(fileId, kAudioFilePropertyEstimatedDuration, &propertySize, &sampleLength);
-    if (errcode) {
-        *error = [reporter
-            errorWithCode:kDEFileFormatReadError
-            description:@"Failed to read sound length."];
-        AudioFileClose(fileId);
-        return nil;
-    }
-
-    UInt32 dataSize = (UInt32) fileSize;
-    void *data = malloc(dataSize);
-    if (!data) {
-        *error = [reporter errorWithCode:kDEMemoryAllocationError];
-        AudioFileClose(fileId);
-        return nil;
-    }
-    
-    errcode = AudioFileReadBytes(fileId, false, 0, &dataSize, data);
-    if (errcode) {
-        *error = [reporter
-            errorWithCode:kDEFileFormatReadError
-            description:@"Failed to read sound data."];
-        free(data);
-        AudioFileClose(fileId);
-        return nil;
-    }
-
-    Sample *sample = [[Sample alloc] init];
-    [sample setChannels:fileFormat.mChannelsPerFrame];
-    [sample setEndianity:TestAudioFormatNativeEndian(fileFormat) ? kLittleEndian : kBigEndian];
-    [sample setBitsPerChannel:fileFormat.mBitsPerChannel];
-    [sample setSampleRate:fileFormat.mSampleRate];
-    [sample setDuration:sampleLength];
-    [sample setData:[NSData dataWithBytesNoCopy:data length:dataSize freeWhenDone:YES]];
-    
-    AudioFileClose(fileId);
-    return [sample autorelease];
+   OSStatus errcode = noErr;
+   UInt32 propertySize;
+   ExtAudioFileRef fileRef = 0;
+   Reporter *reporter = [Reporter forDomain:@"Sample Decoder" error:error];
+   
+   errcode = ExtAudioFileOpenURL((CFURLRef) fileURL, &fileRef);
+   if (errcode) {
+       *error = [reporter errorWithCode:kDEFileReadError];
+       return nil;
+   }
+   
+   AudioStreamBasicDescription fileFormat;
+   propertySize = sizeof(fileFormat);
+   errcode = ExtAudioFileGetProperty(fileRef, kExtAudioFileProperty_FileDataFormat, &propertySize, &fileFormat);
+   if (errcode) {
+       *error = [reporter errorWithCode:kDEFileFormatReadError];
+       ExtAudioFileDispose(fileRef);
+       return nil;
+   }
+   
+   if (fileFormat.mChannelsPerFrame > 2) {
+       *error = [reporter
+                           errorWithCode:kDEFileFormatReadError
+                           description:@"Too many channels (better than stereo!)."];
+       ExtAudioFileDispose(fileRef);
+       return nil;
+   }
+   
+   AudioStreamBasicDescription theOutputFormat;
+   
+   theOutputFormat.mSampleRate = fileFormat.mSampleRate;
+   theOutputFormat.mChannelsPerFrame = fileFormat.mChannelsPerFrame;
+   
+   theOutputFormat.mFormatID = kAudioFormatLinearPCM;
+   theOutputFormat.mBytesPerPacket = 2 * theOutputFormat.mChannelsPerFrame;
+   theOutputFormat.mFramesPerPacket = 1;
+   theOutputFormat.mBytesPerFrame = 2 * theOutputFormat.mChannelsPerFrame;
+   theOutputFormat.mBitsPerChannel = 16;
+   theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
+   
+   errcode = ExtAudioFileSetProperty(fileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(theOutputFormat), &theOutputFormat);
+   if (errcode) {
+       *error = [reporter
+                           errorWithCode:kDEFileFormatReadError
+                           description:@"Couldn't set output format..."];
+       ExtAudioFileDispose(fileRef);
+       return nil;     
+   }
+   
+   
+   // Get the total frame count
+   SInt64 numFrames;
+   propertySize = sizeof(numFrames);
+   errcode = ExtAudioFileGetProperty(fileRef, kExtAudioFileProperty_FileLengthFrames, &propertySize, &numFrames);
+   if (errcode) {
+       *error = [reporter
+                           errorWithCode:kDEFileFormatReadError
+                           description:@"Couldn't set output format..."];
+       ExtAudioFileDispose(fileRef);
+       return nil;
+   }
+   
+   // Read all the data into memory
+   UInt64 dataSize = numFrames * theOutputFormat.mBytesPerFrame;
+   void *data = malloc(dataSize);
+   
+   ALsizei outDataSize;
+   ALenum outFormat;
+   ALsizei outSampleRate;
+   
+   if (data) {
+       AudioBufferList     theDataBuffer;
+       theDataBuffer.mNumberBuffers = 1;
+       theDataBuffer.mBuffers[0].mDataByteSize = dataSize;
+       theDataBuffer.mBuffers[0].mNumberChannels = theOutputFormat.mChannelsPerFrame;
+       theDataBuffer.mBuffers[0].mData = data;
+       
+       // Read the data into an AudioBufferList
+       errcode = ExtAudioFileRead(fileRef, (UInt32*)&numFrames, &theDataBuffer);
+       if(errcode == noErr)
+       {
+           // success
+           outDataSize = (ALsizei)dataSize;
+           outFormat = (theOutputFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
+           outSampleRate = (ALsizei)theOutputFormat.mSampleRate;
+       }
+       else
+       {
+           // failure
+           free (data);
+           data = nil;
+           *error = [reporter
+                               errorWithCode:kDEFileFormatReadError
+                               description:@"Couldn't set output format..."];
+           ExtAudioFileDispose(fileRef);
+           return nil;
+       }
+   }
+   
+   Sample *sample = [[Sample alloc] init];
+   [sample setChannels:theOutputFormat.mChannelsPerFrame];
+   [sample setEndianity:TestAudioFormatNativeEndian(theOutputFormat) ? kLittleEndian : kBigEndian];
+   [sample setBitsPerChannel:theOutputFormat.mBitsPerChannel];
+   [sample setSampleRate:theOutputFormat.mSampleRate];
+   //[sample setDuration:sampleLength];
+   [sample setData:[NSData dataWithBytesNoCopy:data length:dataSize freeWhenDone:YES]];
+   
+   ExtAudioFileDispose(fileRef);
+   return [sample autorelease];
 }
 
 + (void) load
diff --git a/Source/Sound.h b/Source/Sound.h
index 124ee6a..aa4b8ed 100644
--- a/Source/Sound.h
+++ b/Source/Sound.h
@@ -41,5 +41,6 @@ enum SoundError {
 
 - (void) play;
 - (void) stop;
+- (void) pause;
 
 @end
diff --git a/Source/Sound.m b/Source/Sound.m
index b552834..4bc5ff7 100644
--- a/Source/Sound.m
+++ b/Source/Sound.m
@@ -159,4 +159,13 @@
     [self checkSuccessOrLog:@"Failed to stop sound"];
 }
 
+- (void) pause
+{
+   if (!self.playing)
+       return;
+   CLEAR_ERROR_FLAG;
+   alSourcePause(source);
+   [self checkSuccessOrLog:@"Failed to pause sound"];
+}
+
 @end

@BobDG
Copy link

BobDG commented Jul 12, 2013

Does anybody have a working example with the code from nornagon? I can't seem to get it to work!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants