├── Classes ├── BJIConverter.h ├── BJIConverter.m ├── MixTwoAudioFilesDemoAppDelegate.h ├── MixTwoAudioFilesDemoAppDelegate.m ├── MixTwoAudioFilesDemoViewController.h ├── MixTwoAudioFilesDemoViewController.m ├── PCMMixer.h └── PCMMixer.m ├── Info.plist ├── MainWindow.xib ├── MixTwoAudioFilesDemo.xcodeproj └── project.pbxproj ├── MixTwoAudioFilesDemoViewController.xib ├── MixTwoAudioFilesDemo_Prefix.pch ├── README ├── funk.mp3 ├── main.m ├── tk.mp3 └── toms.mp3 /Classes/BJIConverter.h: -------------------------------------------------------------------------------- 1 | // 2 | // BJIConverter.h 3 | // audioTest 4 | // 5 | // Created by Jean-Pierre Simard on 12-07-19. 6 | // Copyright (c) 2012 Magnetic Bear Studios. All rights reserved. 7 | // 8 | 9 | #include 10 | #import 11 | 12 | @interface BJIConverter : NSObject 13 | 14 | typedef struct MyAudioConverterSettings 15 | { 16 | AudioStreamBasicDescription outputFormat; // output file's data stream description 17 | 18 | ExtAudioFileRef inputFile; // reference to your input file 19 | AudioFileID outputFile; // reference to your output file 20 | 21 | } MyAudioConverterSettings; 22 | 23 | void Convert(MyAudioConverterSettings *mySettings); 24 | + (BOOL)convertFile:(NSString*)fileIn toFile:(NSString*)fileOut; 25 | + (BOOL)convertFiles:(NSArray*)filesIn toFiles:(NSArray*)filesOut; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Classes/BJIConverter.m: -------------------------------------------------------------------------------- 1 | // 2 | // BJIConverter.m 3 | // audioTest 4 | // 5 | // Created by Jean-Pierre Simard on 12-07-19. 6 | // Copyright (c) 2012 Magnetic Bear Studios. All rights reserved. 7 | // 8 | 9 | #import "BJIConverter.h" 10 | 11 | @implementation BJIConverter 12 | 13 | #pragma mark - utility functions - 14 | 15 | // generic error handler - if result is nonzero, prints error message and exits program. 16 | static void CheckResult(OSStatus result, const char *operation) 17 | { 18 | if (result == noErr) return; 19 | 20 | char errorString[20]; 21 | // see if it appears to be a 4-char-code 22 | *(UInt32 *)(errorString + 1) = CFSwapInt32HostToBig(result); 23 | if (isprint(errorString[1]) && isprint(errorString[2]) && isprint(errorString[3]) && isprint(errorString[4])) { 24 | errorString[0] = errorString[5] = '\''; 25 | errorString[6] = '\0'; 26 | } else 27 | // no, format it as an integer 28 | sprintf(errorString, "%d", (int)result); 29 | 30 | fprintf(stderr, "Error: %s (%s)\n", operation, errorString); 31 | 32 | exit(1); 33 | } 34 | 35 | #pragma mark - audio converter - 36 | void Convert(MyAudioConverterSettings *mySettings) 37 | { 38 | 39 | UInt32 outputBufferSize = 32 * 1024; // 32 KB is a good starting point 40 | UInt32 sizePerPacket = mySettings->outputFormat.mBytesPerPacket; 41 | UInt32 packetsPerBuffer = outputBufferSize / sizePerPacket; 42 | 43 | // allocate destination buffer 44 | UInt8 *outputBuffer = (UInt8 *)malloc(sizeof(UInt8) * outputBufferSize); 45 | 46 | UInt32 outputFilePacketPosition = 0; //in bytes 47 | while(1) 48 | { 49 | // wrap the destination buffer in an AudioBufferList 50 | AudioBufferList convertedData; 51 | convertedData.mNumberBuffers = 1; 52 | convertedData.mBuffers[0].mNumberChannels = mySettings->outputFormat.mChannelsPerFrame; 53 | convertedData.mBuffers[0].mDataByteSize = outputBufferSize; 54 | convertedData.mBuffers[0].mData = outputBuffer; 55 | 56 | UInt32 frameCount = packetsPerBuffer; 57 | 58 | // read from the extaudiofile 59 | CheckResult(ExtAudioFileRead(mySettings->inputFile, 60 | &frameCount, 61 | &convertedData), 62 | "Couldn't read from input file"); 63 | 64 | if (frameCount == 0) { 65 | printf ("done reading from file"); 66 | return; 67 | } 68 | 69 | // write the converted data to the output file 70 | CheckResult (AudioFileWritePackets(mySettings->outputFile, 71 | FALSE, 72 | frameCount, 73 | NULL, 74 | outputFilePacketPosition / mySettings->outputFormat.mBytesPerPacket, 75 | &frameCount, 76 | convertedData.mBuffers[0].mData), 77 | "Couldn't write packets to file"); 78 | 79 | // advance the output file write location 80 | outputFilePacketPosition += (frameCount * mySettings->outputFormat.mBytesPerPacket); 81 | } 82 | 83 | // AudioConverterDispose(audioConverter); 84 | } 85 | 86 | + (BOOL)convertFile:(NSString*)fileIn toFile:(NSString*)fileOut { 87 | MyAudioConverterSettings audioConverterSettings = {0}; 88 | // open the input with ExtAudioFile 89 | CFURLRef inputFileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)fileIn, kCFURLPOSIXPathStyle, false); 90 | CheckResult(ExtAudioFileOpenURL(inputFileURL, 91 | &audioConverterSettings.inputFile), 92 | "ExtAudioFileOpenURL failed"); 93 | CFRelease(inputFileURL); 94 | 95 | if ([fileOut rangeOfString:@".aiff"].location != NSNotFound) { 96 | // define the ouput format. AudioConverter requires that one of the data formats be LPCM 97 | audioConverterSettings.outputFormat.mSampleRate = 44100.0; 98 | audioConverterSettings.outputFormat.mFormatID = kAudioFormatLinearPCM; 99 | audioConverterSettings.outputFormat.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 100 | audioConverterSettings.outputFormat.mBytesPerPacket = 4; 101 | audioConverterSettings.outputFormat.mFramesPerPacket = 1; 102 | audioConverterSettings.outputFormat.mBytesPerFrame = 4; 103 | audioConverterSettings.outputFormat.mChannelsPerFrame = 2; 104 | audioConverterSettings.outputFormat.mBitsPerChannel = 16; 105 | 106 | // create output file 107 | CFURLRef outputFileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)fileOut, kCFURLPOSIXPathStyle, false); 108 | CheckResult (AudioFileCreateWithURL(outputFileURL, kAudioFileAIFFType, &audioConverterSettings.outputFormat, kAudioFileFlags_EraseFile, &audioConverterSettings.outputFile), 109 | "AudioFileCreateWithURL failed"); 110 | CFRelease(outputFileURL); 111 | } else if ([fileOut rangeOfString:@".caf"].location != NSNotFound) { 112 | // define the ouput format. AudioConverter requires that one of the data formats be LPCM 113 | audioConverterSettings.outputFormat.mSampleRate = 44100.0; 114 | audioConverterSettings.outputFormat.mFormatID = kAudioFormatLinearPCM; 115 | audioConverterSettings.outputFormat.mFormatFlags = kAudioFormatFlagsCanonical; 116 | audioConverterSettings.outputFormat.mBytesPerPacket = 4; 117 | audioConverterSettings.outputFormat.mFramesPerPacket = 1; 118 | audioConverterSettings.outputFormat.mBytesPerFrame = 4; 119 | audioConverterSettings.outputFormat.mChannelsPerFrame = 2; 120 | audioConverterSettings.outputFormat.mBitsPerChannel = 16; 121 | 122 | // create output file 123 | CFURLRef outputFileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)fileOut, kCFURLPOSIXPathStyle, false); 124 | CheckResult (AudioFileCreateWithURL(outputFileURL, kAudioFileCAFType, &audioConverterSettings.outputFormat, kAudioFileFlags_EraseFile, &audioConverterSettings.outputFile), 125 | "AudioFileCreateWithURL failed"); 126 | CFRelease(outputFileURL); 127 | } 128 | 129 | // set the PCM format as the client format on the input ext audio file 130 | CheckResult(ExtAudioFileSetProperty(audioConverterSettings.inputFile, 131 | kExtAudioFileProperty_ClientDataFormat, 132 | sizeof (AudioStreamBasicDescription), 133 | &audioConverterSettings.outputFormat), 134 | "Couldn't set client data format on input ext file"); 135 | 136 | fprintf(stdout, "Converting...\n"); 137 | Convert(&audioConverterSettings); 138 | 139 | cleanup: 140 | // AudioFileClose(audioConverterSettings.inputFile); 141 | ExtAudioFileDispose(audioConverterSettings.inputFile); 142 | AudioFileClose(audioConverterSettings.outputFile); 143 | return YES; 144 | } 145 | 146 | + (BOOL)convertFiles:(NSArray*)filesIn toFiles:(NSArray*)filesOut { 147 | [filesIn enumerateObjectsUsingBlock:^(NSString *fileIn, NSUInteger idx, BOOL *stop) { 148 | [self convertFile:fileIn toFile:[filesOut objectAtIndex:idx]]; 149 | }]; 150 | return YES; 151 | } 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /Classes/MixTwoAudioFilesDemoAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // MixTwoAudioFilesDemoAppDelegate.h 3 | // MixTwoAudioFilesDemo 4 | // 5 | // Created by Moses DeJong on 3/25/09. 6 | // 7 | 8 | #import 9 | 10 | @class MixTwoAudioFilesDemoViewController; 11 | @class AVAudioPlayer; 12 | 13 | @interface MixTwoAudioFilesDemoAppDelegate : NSObject { 14 | UIWindow *window; 15 | MixTwoAudioFilesDemoViewController *viewController; 16 | AVAudioPlayer* avAudio; 17 | } 18 | 19 | @property (nonatomic, retain) IBOutlet UIWindow *window; 20 | @property (nonatomic, retain) IBOutlet MixTwoAudioFilesDemoViewController *viewController; 21 | @property (nonatomic, retain) AVAudioPlayer *avAudio; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Classes/MixTwoAudioFilesDemoAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // MixTwoAudioFilesDemoAppDelegate.m 3 | // MixTwoAudioFilesDemo 4 | // 5 | // Created by Moses DeJong on 3/25/09. 6 | // 7 | 8 | #import "MixTwoAudioFilesDemoAppDelegate.h" 9 | #import "MixTwoAudioFilesDemoViewController.h" 10 | #import "PCMMixer.h" 11 | #import "BJIConverter.h" 12 | 13 | #import 14 | 15 | @implementation MixTwoAudioFilesDemoAppDelegate 16 | 17 | @synthesize window; 18 | @synthesize viewController; 19 | @synthesize avAudio; 20 | 21 | - (void)applicationDidFinishLaunching:(UIApplication *)application { 22 | 23 | // Override point for customization after app launch 24 | [window addSubview:viewController.view]; 25 | [window makeKeyAndVisible]; 26 | 27 | NSArray *mp3s = [self getMP3s]; 28 | NSArray *cafs = [self getCAFs:mp3s]; 29 | // Convert all mp3's to cafs 30 | [BJIConverter convertFiles:mp3s toFiles:cafs]; 31 | 32 | NSArray *files = cafs; 33 | NSArray *times = [self getTimes]; 34 | NSString *mixURL = [self getMixURL]; 35 | 36 | OSStatus status = [PCMMixer mixFiles:files atTimes:times toMixfile:mixURL]; 37 | 38 | [self playMix:mixURL withStatus:status]; 39 | [BJIConverter convertFile:mixURL toFile:[mixURL stringByReplacingOccurrencesOfString:@".caf" withString:@".aiff"]]; 40 | } 41 | 42 | - (void)dealloc { 43 | [viewController release]; 44 | [window release]; 45 | [avAudio release]; 46 | [super dealloc]; 47 | } 48 | 49 | - (NSArray*)getFiles { 50 | NSString *inFile = [[NSBundle mainBundle] pathForResource:@"toms.caf" ofType:nil]; 51 | return [NSArray arrayWithObjects:inFile,inFile,inFile,inFile, nil]; 52 | } 53 | 54 | - (NSArray *)getTimes { 55 | // First item must be at time 0. All other sounds must be relative to this first sound. 56 | return [NSArray arrayWithObjects:[NSNumber numberWithInt:0],[NSNumber numberWithInt:10],[NSNumber numberWithInt:20], nil]; 57 | } 58 | 59 | - (NSString*)getMixURL { 60 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 61 | return [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Mix.caf"]; 62 | } 63 | 64 | - (void)playMix:(NSString*)mixURL withStatus:(OSStatus)status { 65 | if (status == OSSTATUS_MIX_WOULD_CLIP) { 66 | [viewController.view setBackgroundColor:[UIColor redColor]]; 67 | } else { 68 | [viewController.view setBackgroundColor:[UIColor greenColor]]; 69 | 70 | NSURL *url = [NSURL fileURLWithPath:mixURL]; 71 | 72 | NSData *urlData = [NSData dataWithContentsOfURL:url]; 73 | 74 | NSLog(@"wrote mix file of size %d : %@", [urlData length], mixURL); 75 | 76 | AVAudioPlayer *avAudioObj = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil]; 77 | [avAudioObj autorelease]; 78 | self.avAudio = avAudioObj; 79 | 80 | [avAudioObj prepareToPlay]; 81 | [avAudioObj play]; 82 | } 83 | } 84 | 85 | - (NSArray*)getMP3s { 86 | // Find all mp3's in bundle 87 | NSString *bundleRoot = [[NSBundle mainBundle] bundlePath]; 88 | NSFileManager *fm = [NSFileManager defaultManager]; 89 | NSArray *dirContents = [fm contentsOfDirectoryAtPath:bundleRoot error:nil]; 90 | NSPredicate *fltr = [NSPredicate predicateWithFormat:@"self ENDSWITH '.mp3'"]; 91 | NSArray *mp3s = [dirContents filteredArrayUsingPredicate:fltr]; 92 | 93 | // Convert mp3's to their full paths 94 | NSMutableArray *fullmp3s = [[NSMutableArray alloc] initWithCapacity:[mp3s count]]; 95 | [mp3s enumerateObjectsUsingBlock:^(NSString *file, NSUInteger idx, BOOL *stop) { 96 | [fullmp3s addObject:[bundleRoot stringByAppendingPathComponent:file]]; 97 | }]; 98 | return fullmp3s; 99 | } 100 | 101 | - (NSArray*)getCAFs:(NSArray*)mp3s { 102 | // Find 'Documents' directory 103 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 104 | NSString *docPath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; 105 | 106 | // Create AIFFs from mp3's 107 | NSMutableArray *cafs = [[NSMutableArray alloc] initWithCapacity:[mp3s count]]; 108 | [mp3s enumerateObjectsUsingBlock:^(NSString *file, NSUInteger idx, BOOL *stop) { 109 | [cafs addObject:[docPath stringByAppendingPathComponent:[[file lastPathComponent] stringByReplacingOccurrencesOfString:@".mp3" withString:@".caf"]]]; 110 | }]; 111 | return cafs; 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /Classes/MixTwoAudioFilesDemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MixTwoAudioFilesDemoViewController.h 3 | // MixTwoAudioFilesDemo 4 | // 5 | // Created by Moses DeJong on 3/25/09. 6 | // 7 | 8 | #import 9 | 10 | @interface MixTwoAudioFilesDemoViewController : UIViewController { 11 | 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Classes/MixTwoAudioFilesDemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MixTwoAudioFilesDemoViewController.m 3 | // MixTwoAudioFilesDemo 4 | // 5 | // Created by Moses DeJong on 3/25/09. 6 | // 7 | 8 | #import "MixTwoAudioFilesDemoViewController.h" 9 | 10 | @implementation MixTwoAudioFilesDemoViewController 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Classes/PCMMixer.h: -------------------------------------------------------------------------------- 1 | // 2 | // PCMMixer.h 3 | // 4 | // Created by Moses DeJong on 3/25/09. 5 | // 6 | 7 | #import 8 | #import 9 | 10 | // Returned as the value of the OSStatus argument to mix when the sound samples 11 | // values would clip when mixed together. If a mix would clip then the output 12 | // file is not generated. 13 | 14 | #define OSSTATUS_MIX_WOULD_CLIP 8888 15 | 16 | 17 | @interface PCMMixer : NSObject { 18 | 19 | } 20 | 21 | + (OSStatus) mix:(NSString*)file1 file2:(NSString*)file2 offset:(int)offset mixfile:(NSString*)mixfile; 22 | + (OSStatus) mixFiles:(NSArray*)files atTimes:(NSArray*)times toMixfile:(NSString*)mixfile; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Classes/PCMMixer.m: -------------------------------------------------------------------------------- 1 | // 2 | // PCMMixer.m 3 | // 4 | // Created by Moses DeJong on 3/25/09. 5 | // 6 | 7 | #import "PCMMixer.h" 8 | 9 | #import 10 | 11 | // Mix sample data from two buffers, if clipping is detected 12 | // then we have to exit the mix operation. 13 | 14 | static 15 | inline 16 | BOOL mix_buffers(const int16_t *buffer1, 17 | const int16_t *buffer2, 18 | int16_t *mixbuffer, 19 | int mixbufferNumSamples) 20 | { 21 | BOOL clipping = FALSE; 22 | 23 | for (int i = 0 ; i < mixbufferNumSamples; i++) { 24 | int32_t s1 = buffer1[i]; 25 | int32_t s2 = buffer2[i]; 26 | int32_t mixed = s1 + s2; 27 | 28 | // Brick wall limiter 29 | if (mixed < -32768) 30 | mixed = -32768; 31 | else if (mixed > 32767) 32 | mixed = 32767; 33 | mixbuffer[i] = (int16_t) mixed; 34 | 35 | // Clipping detection 36 | // if ((mixed < -32768) || (mixed > 32767)) { 37 | // clipping = TRUE; 38 | // break; 39 | // } else { 40 | // mixbuffer[i] = (int16_t) mixed; 41 | // } 42 | } 43 | 44 | return clipping; 45 | } 46 | 47 | @implementation PCMMixer 48 | 49 | + (void) _setDefaultAudioFormatFlags:(AudioStreamBasicDescription*)audioFormatPtr 50 | numChannels:(NSUInteger)numChannels 51 | { 52 | bzero(audioFormatPtr, sizeof(AudioStreamBasicDescription)); 53 | 54 | audioFormatPtr->mFormatID = kAudioFormatLinearPCM; 55 | audioFormatPtr->mSampleRate = 44100.0; 56 | audioFormatPtr->mChannelsPerFrame = numChannels; 57 | audioFormatPtr->mBytesPerPacket = 2 * numChannels; 58 | audioFormatPtr->mFramesPerPacket = 1; 59 | audioFormatPtr->mBytesPerFrame = 2 * numChannels; 60 | audioFormatPtr->mBitsPerChannel = 16; 61 | audioFormatPtr->mFormatFlags = kAudioFormatFlagsNativeEndian | 62 | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; 63 | } 64 | 65 | + (OSStatus) mix:(NSString*)file1 file2:(NSString*)file2 offset:(int)offset mixfile:(NSString*)mixfile 66 | { 67 | OSStatus status, close_status; 68 | 69 | NSURL *url1 = [NSURL fileURLWithPath:file1]; 70 | NSURL *url2 = [NSURL fileURLWithPath:file2]; 71 | NSURL *mixURL = [NSURL fileURLWithPath:mixfile]; 72 | 73 | AudioFileID inAudioFile1 = NULL; 74 | AudioFileID inAudioFile2 = NULL; 75 | AudioFileID mixAudioFile = NULL; 76 | 77 | #ifndef TARGET_OS_IPHONE 78 | // Why is this constant missing under Mac OS X? 79 | # define kAudioFileReadPermission fsRdPerm 80 | #endif 81 | 82 | #define BUFFER_SIZE 1024 83 | char *buffer1 = NULL; 84 | char *buffer2 = NULL; 85 | char *mixbuffer = NULL; 86 | 87 | status = AudioFileOpenURL((CFURLRef)url1, kAudioFileReadPermission, 0, &inAudioFile1); 88 | if (status) 89 | { 90 | goto reterr; 91 | } 92 | 93 | status = AudioFileOpenURL((CFURLRef)url2, kAudioFileReadPermission, 0, &inAudioFile2); 94 | if (status) 95 | { 96 | goto reterr; 97 | } 98 | 99 | // Verify that file contains pcm data at 44 kHz 100 | 101 | AudioStreamBasicDescription inputDataFormat; 102 | UInt32 propSize = sizeof(inputDataFormat); 103 | 104 | bzero(&inputDataFormat, sizeof(inputDataFormat)); 105 | status = AudioFileGetProperty(inAudioFile1, kAudioFilePropertyDataFormat, 106 | &propSize, &inputDataFormat); 107 | 108 | if (status) 109 | { 110 | goto reterr; 111 | } 112 | 113 | if ((inputDataFormat.mFormatID == kAudioFormatLinearPCM) && 114 | (inputDataFormat.mSampleRate == 44100.0) && 115 | (inputDataFormat.mChannelsPerFrame == 2) && 116 | (inputDataFormat.mChannelsPerFrame == 2) && 117 | (inputDataFormat.mBitsPerChannel == 16) && 118 | (inputDataFormat.mFormatFlags == (kAudioFormatFlagsNativeEndian | 119 | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger)) 120 | ) { 121 | // no-op when the expected data format is found 122 | } else { 123 | status = kAudioFileUnsupportedFileTypeError; 124 | goto reterr; 125 | } 126 | 127 | // Do the same for file2 128 | 129 | propSize = sizeof(inputDataFormat); 130 | 131 | bzero(&inputDataFormat, sizeof(inputDataFormat)); 132 | status = AudioFileGetProperty(inAudioFile2, kAudioFilePropertyDataFormat, 133 | &propSize, &inputDataFormat); 134 | 135 | if (status) 136 | { 137 | goto reterr; 138 | } 139 | 140 | if ((inputDataFormat.mFormatID == kAudioFormatLinearPCM) && 141 | (inputDataFormat.mSampleRate == 44100.0) && 142 | (inputDataFormat.mChannelsPerFrame == 2) && 143 | (inputDataFormat.mChannelsPerFrame == 2) && 144 | (inputDataFormat.mBitsPerChannel == 16) && 145 | (inputDataFormat.mFormatFlags == (kAudioFormatFlagsNativeEndian | 146 | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger)) 147 | ) { 148 | // no-op when the expected data format is found 149 | } else { 150 | status = kAudioFileUnsupportedFileTypeError; 151 | goto reterr; 152 | } 153 | 154 | // Both input files validated, open output (mix) file 155 | 156 | [self _setDefaultAudioFormatFlags:&inputDataFormat numChannels:2]; 157 | 158 | status = AudioFileCreateWithURL((CFURLRef)mixURL, kAudioFileCAFType, &inputDataFormat, 159 | kAudioFileFlags_EraseFile, &mixAudioFile); 160 | if (status) 161 | { 162 | goto reterr; 163 | } 164 | 165 | // Read buffer of data from each file 166 | 167 | buffer1 = malloc(BUFFER_SIZE); 168 | assert(buffer1); 169 | buffer2 = malloc(BUFFER_SIZE); 170 | assert(buffer2); 171 | mixbuffer = malloc(BUFFER_SIZE); 172 | assert(mixbuffer); 173 | 174 | SInt64 packetNum1 = 0; 175 | SInt64 packetNum2 = 0; 176 | SInt64 mixpacketNum = 0; 177 | 178 | while (TRUE) { 179 | // Read a chunk of input 180 | 181 | UInt32 bytesRead1 = 0; 182 | UInt32 bytesRead2 = 0; 183 | UInt32 numPackets1 = 0; 184 | UInt32 numPackets2 = 0; 185 | 186 | numPackets1 = BUFFER_SIZE / inputDataFormat.mBytesPerPacket; 187 | status = AudioFileReadPackets(inAudioFile1, 188 | false, 189 | &bytesRead1, 190 | NULL, 191 | packetNum1, 192 | &numPackets1, 193 | buffer1); 194 | 195 | if (status) { 196 | goto reterr; 197 | } 198 | 199 | // if buffer was not filled, fill with zeros 200 | 201 | if (bytesRead1 < BUFFER_SIZE) { 202 | bzero(buffer1 + bytesRead1, (BUFFER_SIZE - bytesRead1)); 203 | } 204 | 205 | packetNum1 += numPackets1; 206 | if (mixpacketNum > offset*BUFFER_SIZE) { 207 | numPackets2 = BUFFER_SIZE / inputDataFormat.mBytesPerPacket; 208 | status = AudioFileReadPackets(inAudioFile2, 209 | false, 210 | &bytesRead2, 211 | NULL, 212 | packetNum2, 213 | &numPackets2, 214 | buffer2); 215 | 216 | if (status) { 217 | goto reterr; 218 | } 219 | } else { 220 | bytesRead2 = 0; 221 | } 222 | 223 | // if buffer was not filled, fill with zeros 224 | 225 | if (bytesRead2 < BUFFER_SIZE) { 226 | bzero(buffer2 + bytesRead2, (BUFFER_SIZE - bytesRead2)); 227 | } 228 | 229 | packetNum2 += numPackets2; 230 | 231 | // If no frames were returned, conversion is finished 232 | if (numPackets1 == 0 && numPackets2 == 0 && packetNum2 > 0) 233 | break; 234 | 235 | // Write pcm data to output file 236 | 237 | int maxNumPackets; 238 | if (numPackets1 > numPackets2) { 239 | maxNumPackets = numPackets1; 240 | } else if (numPackets1 == 0 && numPackets2 == 0) { 241 | maxNumPackets = 1; 242 | } else { 243 | maxNumPackets = numPackets2; 244 | } 245 | 246 | int numSamples = (maxNumPackets * inputDataFormat.mBytesPerPacket) / sizeof(int16_t); 247 | 248 | BOOL clipping = mix_buffers((const int16_t *)buffer1, (const int16_t *)buffer2, 249 | (int16_t *) mixbuffer, numSamples); 250 | 251 | if (clipping) { 252 | status = OSSTATUS_MIX_WOULD_CLIP; 253 | goto reterr; 254 | } 255 | 256 | // write the mixed packets to the output file 257 | 258 | UInt32 packetsWritten = maxNumPackets; 259 | 260 | status = AudioFileWritePackets(mixAudioFile, 261 | FALSE, 262 | (maxNumPackets * inputDataFormat.mBytesPerPacket), 263 | NULL, 264 | mixpacketNum, 265 | &packetsWritten, 266 | mixbuffer); 267 | 268 | if (status) { 269 | goto reterr; 270 | } 271 | 272 | if (packetsWritten != maxNumPackets) { 273 | status = kAudioFileInvalidPacketOffsetError; 274 | goto reterr; 275 | } 276 | 277 | mixpacketNum += packetsWritten; 278 | } 279 | 280 | reterr: 281 | if (inAudioFile1 != NULL) { 282 | close_status = AudioFileClose(inAudioFile1); 283 | assert(close_status == 0); 284 | } 285 | if (inAudioFile2 != NULL) { 286 | close_status = AudioFileClose(inAudioFile2); 287 | assert(close_status == 0); 288 | } 289 | if (mixAudioFile != NULL) { 290 | close_status = AudioFileClose(mixAudioFile); 291 | assert(close_status == 0); 292 | } 293 | if (status == OSSTATUS_MIX_WOULD_CLIP) { 294 | char *mixfile_str = (char*) [mixfile UTF8String]; 295 | close_status = unlink(mixfile_str); 296 | assert(close_status == 0); 297 | } 298 | if (buffer1 != NULL) { 299 | free(buffer1); 300 | } 301 | if (buffer2 != NULL) { 302 | free(buffer2); 303 | } 304 | if (mixbuffer != NULL) { 305 | free(mixbuffer); 306 | } 307 | 308 | return status; 309 | } 310 | 311 | + (OSStatus) mixFiles:(NSArray*)files atTimes:(NSArray*)times toMixfile:(NSString*)mixfile { 312 | OSStatus status; 313 | NSString *tmpDir = NSTemporaryDirectory(); 314 | for (int i=1; i<[files count]; i++) { 315 | NSString *file1 = [tmpDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%d.caf",i-1]]; 316 | NSString *file2 = [files objectAtIndex:i]; 317 | if (i==1) file1 = [files objectAtIndex:0]; 318 | NSString *target = [tmpDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%d.caf",i]]; 319 | if (i+1==[files count]) { 320 | target = mixfile; 321 | } 322 | status = [self mix:file1 file2:file2 offset:[(NSNumber*)[times objectAtIndex:i] intValue]*5 mixfile:target]; 323 | } 324 | return status; 325 | } 326 | 327 | @end 328 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.helpurock.MixTwoAudioFilesDemo 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile 28 | MainWindow 29 | 30 | 31 | -------------------------------------------------------------------------------- /MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 528 5 | 9E17 6 | 672 7 | 949.33 8 | 352.00 9 | 10 | YES 11 | 12 | 13 | 14 | YES 15 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 16 | 17 | 18 | YES 19 | 20 | IBFilesOwner 21 | 22 | 23 | IBFirstResponder 24 | 25 | 26 | 27 | MixTwoAudioFilesDemoViewController 28 | 29 | 30 | 31 | 32 | 292 33 | {320, 480} 34 | 35 | 1 36 | MSAxIDEAA 37 | 38 | NO 39 | NO 40 | 41 | 42 | 43 | 44 | 45 | YES 46 | 47 | 48 | delegate 49 | 50 | 51 | 52 | 4 53 | 54 | 55 | 56 | viewController 57 | 58 | 59 | 60 | 11 61 | 62 | 63 | 64 | window 65 | 66 | 67 | 68 | 14 69 | 70 | 71 | 72 | 73 | YES 74 | 75 | 0 76 | 77 | YES 78 | 79 | 80 | 81 | 82 | 83 | -1 84 | 85 | 86 | RmlsZSdzIE93bmVyA 87 | 88 | 89 | 3 90 | 91 | 92 | MixTwoAudioFilesDemo App Delegate 93 | 94 | 95 | -2 96 | 97 | 98 | 99 | 100 | 10 101 | 102 | 103 | 104 | 105 | 12 106 | 107 | 108 | 109 | 110 | 111 | 112 | YES 113 | 114 | YES 115 | -1.CustomClassName 116 | -2.CustomClassName 117 | 10.CustomClassName 118 | 10.IBEditorWindowLastContentRect 119 | 10.IBPluginDependency 120 | 12.IBEditorWindowLastContentRect 121 | 12.IBPluginDependency 122 | 3.CustomClassName 123 | 3.IBPluginDependency 124 | 125 | 126 | YES 127 | UIApplication 128 | UIResponder 129 | MixTwoAudioFilesDemoViewController 130 | {{512, 351}, {320, 480}} 131 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 132 | {{525, 346}, {320, 480}} 133 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 134 | MixTwoAudioFilesDemoAppDelegate 135 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 136 | 137 | 138 | 139 | YES 140 | 141 | YES 142 | 143 | 144 | YES 145 | 146 | 147 | 148 | 149 | YES 150 | 151 | YES 152 | 153 | 154 | YES 155 | 156 | 157 | 158 | 14 159 | 160 | 161 | 162 | YES 163 | 164 | MixTwoAudioFilesDemoAppDelegate 165 | NSObject 166 | 167 | YES 168 | 169 | YES 170 | viewController 171 | window 172 | 173 | 174 | YES 175 | MixTwoAudioFilesDemoViewController 176 | UIWindow 177 | 178 | 179 | 180 | IBProjectSource 181 | Classes/MixTwoAudioFilesDemoAppDelegate.h 182 | 183 | 184 | 185 | MixTwoAudioFilesDemoAppDelegate 186 | NSObject 187 | 188 | IBUserSource 189 | 190 | 191 | 192 | 193 | MixTwoAudioFilesDemoViewController 194 | UIViewController 195 | 196 | IBProjectSource 197 | Classes/MixTwoAudioFilesDemoViewController.h 198 | 199 | 200 | 201 | 202 | 0 203 | MixTwoAudioFilesDemo.xcodeproj 204 | 3 205 | 206 | 207 | -------------------------------------------------------------------------------- /MixTwoAudioFilesDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D3623260D0F684500981E51 /* MixTwoAudioFilesDemoAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* MixTwoAudioFilesDemoAppDelegate.m */; }; 11 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 12 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 13 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 14 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; 15 | 2899E5220DE3E06400AC0155 /* MixTwoAudioFilesDemoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2899E5210DE3E06400AC0155 /* MixTwoAudioFilesDemoViewController.xib */; }; 16 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; 17 | 28D7ACF80DDB3853001CB0EB /* MixTwoAudioFilesDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* MixTwoAudioFilesDemoViewController.m */; }; 18 | CDE99D330F7B3E9900550CCF /* PCMMixer.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE99D320F7B3E9900550CCF /* PCMMixer.m */; }; 19 | CDE99D430F7B419A00550CCF /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDE99D420F7B419A00550CCF /* AVFoundation.framework */; }; 20 | CDE99D550F7B43F200550CCF /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDE99D540F7B43F200550CCF /* AudioToolbox.framework */; }; 21 | E88922AC15B908450065A3CA /* tk.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = E88922AA15B908450065A3CA /* tk.mp3 */; }; 22 | E88922AD15B908450065A3CA /* funk.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = E88922AB15B908450065A3CA /* funk.mp3 */; }; 23 | E88922B415B908AA0065A3CA /* BJIConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = E88922B315B908AA0065A3CA /* BJIConverter.m */; }; 24 | E88922B915B90A080065A3CA /* toms.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = E88922B815B90A080065A3CA /* toms.mp3 */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 29 | 1D3623240D0F684500981E51 /* MixTwoAudioFilesDemoAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MixTwoAudioFilesDemoAppDelegate.h; sourceTree = ""; }; 30 | 1D3623250D0F684500981E51 /* MixTwoAudioFilesDemoAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MixTwoAudioFilesDemoAppDelegate.m; sourceTree = ""; }; 31 | 1D6058910D05DD3D006BFB54 /* MixTwoAudioFilesDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MixTwoAudioFilesDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 33 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 34 | 2899E5210DE3E06400AC0155 /* MixTwoAudioFilesDemoViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MixTwoAudioFilesDemoViewController.xib; sourceTree = ""; }; 35 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 36 | 28D7ACF60DDB3853001CB0EB /* MixTwoAudioFilesDemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MixTwoAudioFilesDemoViewController.h; sourceTree = ""; }; 37 | 28D7ACF70DDB3853001CB0EB /* MixTwoAudioFilesDemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MixTwoAudioFilesDemoViewController.m; sourceTree = ""; }; 38 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 39 | 32CA4F630368D1EE00C91783 /* MixTwoAudioFilesDemo_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MixTwoAudioFilesDemo_Prefix.pch; sourceTree = ""; }; 40 | 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | CDE99D310F7B3E9900550CCF /* PCMMixer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCMMixer.h; sourceTree = ""; }; 42 | CDE99D320F7B3E9900550CCF /* PCMMixer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCMMixer.m; sourceTree = ""; }; 43 | CDE99D420F7B419A00550CCF /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 44 | CDE99D540F7B43F200550CCF /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 45 | E88922AA15B908450065A3CA /* tk.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = tk.mp3; sourceTree = ""; }; 46 | E88922AB15B908450065A3CA /* funk.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = funk.mp3; sourceTree = ""; }; 47 | E88922B215B908AA0065A3CA /* BJIConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BJIConverter.h; sourceTree = ""; }; 48 | E88922B315B908AA0065A3CA /* BJIConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BJIConverter.m; sourceTree = ""; }; 49 | E88922B815B90A080065A3CA /* toms.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = toms.mp3; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 58 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 59 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, 60 | CDE99D430F7B419A00550CCF /* AVFoundation.framework in Frameworks */, 61 | CDE99D550F7B43F200550CCF /* AudioToolbox.framework in Frameworks */, 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 080E96DDFE201D6D7F000001 /* Classes */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | E88922B515B908AD0065A3CA /* BJIConverter */, 72 | E88922AE15B9085A0065A3CA /* PCMMixer */, 73 | E88922AF15B908690065A3CA /* App Delegate */, 74 | E88922B015B908720065A3CA /* MixTwoAudioFilesDemoViewController */, 75 | ); 76 | path = Classes; 77 | sourceTree = ""; 78 | }; 79 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 1D6058910D05DD3D006BFB54 /* MixTwoAudioFilesDemo.app */, 83 | ); 84 | name = Products; 85 | sourceTree = ""; 86 | }; 87 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 080E96DDFE201D6D7F000001 /* Classes */, 91 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 92 | 29B97317FDCFA39411CA2CEA /* Resources */, 93 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 94 | 19C28FACFE9D520D11CA2CBB /* Products */, 95 | ); 96 | name = CustomTemplate; 97 | sourceTree = ""; 98 | }; 99 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 32CA4F630368D1EE00C91783 /* MixTwoAudioFilesDemo_Prefix.pch */, 103 | 29B97316FDCFA39411CA2CEA /* main.m */, 104 | ); 105 | name = "Other Sources"; 106 | sourceTree = ""; 107 | }; 108 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | E88922B115B908800065A3CA /* Audio */, 112 | 2899E5210DE3E06400AC0155 /* MixTwoAudioFilesDemoViewController.xib */, 113 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */, 114 | 8D1107310486CEB800E47090 /* Info.plist */, 115 | ); 116 | name = Resources; 117 | sourceTree = ""; 118 | }; 119 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | CDE99D540F7B43F200550CCF /* AudioToolbox.framework */, 123 | CDE99D420F7B419A00550CCF /* AVFoundation.framework */, 124 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 125 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 126 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */, 127 | ); 128 | name = Frameworks; 129 | sourceTree = ""; 130 | }; 131 | E88922AE15B9085A0065A3CA /* PCMMixer */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | CDE99D310F7B3E9900550CCF /* PCMMixer.h */, 135 | CDE99D320F7B3E9900550CCF /* PCMMixer.m */, 136 | ); 137 | name = PCMMixer; 138 | sourceTree = ""; 139 | }; 140 | E88922AF15B908690065A3CA /* App Delegate */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 1D3623240D0F684500981E51 /* MixTwoAudioFilesDemoAppDelegate.h */, 144 | 1D3623250D0F684500981E51 /* MixTwoAudioFilesDemoAppDelegate.m */, 145 | ); 146 | name = "App Delegate"; 147 | sourceTree = ""; 148 | }; 149 | E88922B015B908720065A3CA /* MixTwoAudioFilesDemoViewController */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 28D7ACF60DDB3853001CB0EB /* MixTwoAudioFilesDemoViewController.h */, 153 | 28D7ACF70DDB3853001CB0EB /* MixTwoAudioFilesDemoViewController.m */, 154 | ); 155 | name = MixTwoAudioFilesDemoViewController; 156 | sourceTree = ""; 157 | }; 158 | E88922B115B908800065A3CA /* Audio */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | E88922B815B90A080065A3CA /* toms.mp3 */, 162 | E88922AA15B908450065A3CA /* tk.mp3 */, 163 | E88922AB15B908450065A3CA /* funk.mp3 */, 164 | ); 165 | name = Audio; 166 | sourceTree = ""; 167 | }; 168 | E88922B515B908AD0065A3CA /* BJIConverter */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | E88922B215B908AA0065A3CA /* BJIConverter.h */, 172 | E88922B315B908AA0065A3CA /* BJIConverter.m */, 173 | ); 174 | name = BJIConverter; 175 | sourceTree = ""; 176 | }; 177 | /* End PBXGroup section */ 178 | 179 | /* Begin PBXNativeTarget section */ 180 | 1D6058900D05DD3D006BFB54 /* MixTwoAudioFilesDemo */ = { 181 | isa = PBXNativeTarget; 182 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "MixTwoAudioFilesDemo" */; 183 | buildPhases = ( 184 | 1D60588D0D05DD3D006BFB54 /* Resources */, 185 | 1D60588E0D05DD3D006BFB54 /* Sources */, 186 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 187 | ); 188 | buildRules = ( 189 | ); 190 | dependencies = ( 191 | ); 192 | name = MixTwoAudioFilesDemo; 193 | productName = MixTwoAudioFilesDemo; 194 | productReference = 1D6058910D05DD3D006BFB54 /* MixTwoAudioFilesDemo.app */; 195 | productType = "com.apple.product-type.application"; 196 | }; 197 | /* End PBXNativeTarget section */ 198 | 199 | /* Begin PBXProject section */ 200 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 201 | isa = PBXProject; 202 | attributes = { 203 | LastUpgradeCheck = 0430; 204 | }; 205 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MixTwoAudioFilesDemo" */; 206 | compatibilityVersion = "Xcode 3.2"; 207 | developmentRegion = English; 208 | hasScannedForEncodings = 1; 209 | knownRegions = ( 210 | English, 211 | Japanese, 212 | French, 213 | German, 214 | ); 215 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 216 | projectDirPath = ""; 217 | projectRoot = ""; 218 | targets = ( 219 | 1D6058900D05DD3D006BFB54 /* MixTwoAudioFilesDemo */, 220 | ); 221 | }; 222 | /* End PBXProject section */ 223 | 224 | /* Begin PBXResourcesBuildPhase section */ 225 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 226 | isa = PBXResourcesBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, 230 | 2899E5220DE3E06400AC0155 /* MixTwoAudioFilesDemoViewController.xib in Resources */, 231 | E88922AC15B908450065A3CA /* tk.mp3 in Resources */, 232 | E88922AD15B908450065A3CA /* funk.mp3 in Resources */, 233 | E88922B915B90A080065A3CA /* toms.mp3 in Resources */, 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | /* End PBXResourcesBuildPhase section */ 238 | 239 | /* Begin PBXSourcesBuildPhase section */ 240 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 241 | isa = PBXSourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 245 | 1D3623260D0F684500981E51 /* MixTwoAudioFilesDemoAppDelegate.m in Sources */, 246 | 28D7ACF80DDB3853001CB0EB /* MixTwoAudioFilesDemoViewController.m in Sources */, 247 | CDE99D330F7B3E9900550CCF /* PCMMixer.m in Sources */, 248 | E88922B415B908AA0065A3CA /* BJIConverter.m in Sources */, 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | /* End PBXSourcesBuildPhase section */ 253 | 254 | /* Begin XCBuildConfiguration section */ 255 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | COPY_PHASE_STRIP = NO; 260 | GCC_DYNAMIC_NO_PIC = NO; 261 | GCC_OPTIMIZATION_LEVEL = 0; 262 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 263 | GCC_PREFIX_HEADER = MixTwoAudioFilesDemo_Prefix.pch; 264 | INFOPLIST_FILE = Info.plist; 265 | PRODUCT_NAME = MixTwoAudioFilesDemo; 266 | }; 267 | name = Debug; 268 | }; 269 | 1D6058950D05DD3E006BFB54 /* Release */ = { 270 | isa = XCBuildConfiguration; 271 | buildSettings = { 272 | ALWAYS_SEARCH_USER_PATHS = NO; 273 | COPY_PHASE_STRIP = YES; 274 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 275 | GCC_PREFIX_HEADER = MixTwoAudioFilesDemo_Prefix.pch; 276 | INFOPLIST_FILE = Info.plist; 277 | PRODUCT_NAME = MixTwoAudioFilesDemo; 278 | }; 279 | name = Release; 280 | }; 281 | C01FCF4F08A954540054247B /* Debug */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 285 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 286 | GCC_C_LANGUAGE_STANDARD = c99; 287 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 288 | GCC_WARN_UNUSED_VARIABLE = YES; 289 | ONLY_ACTIVE_ARCH = YES; 290 | "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; 291 | SDKROOT = iphoneos; 292 | }; 293 | name = Debug; 294 | }; 295 | C01FCF5008A954540054247B /* Release */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 299 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 300 | GCC_C_LANGUAGE_STANDARD = c99; 301 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; 304 | SDKROOT = iphoneos; 305 | }; 306 | name = Release; 307 | }; 308 | /* End XCBuildConfiguration section */ 309 | 310 | /* Begin XCConfigurationList section */ 311 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "MixTwoAudioFilesDemo" */ = { 312 | isa = XCConfigurationList; 313 | buildConfigurations = ( 314 | 1D6058940D05DD3E006BFB54 /* Debug */, 315 | 1D6058950D05DD3E006BFB54 /* Release */, 316 | ); 317 | defaultConfigurationIsVisible = 0; 318 | defaultConfigurationName = Release; 319 | }; 320 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MixTwoAudioFilesDemo" */ = { 321 | isa = XCConfigurationList; 322 | buildConfigurations = ( 323 | C01FCF4F08A954540054247B /* Debug */, 324 | C01FCF5008A954540054247B /* Release */, 325 | ); 326 | defaultConfigurationIsVisible = 0; 327 | defaultConfigurationName = Release; 328 | }; 329 | /* End XCConfigurationList section */ 330 | }; 331 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 332 | } 333 | -------------------------------------------------------------------------------- /MixTwoAudioFilesDemoViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 528 5 | 9E17 6 | 672 7 | 949.33 8 | 352.00 9 | 10 | YES 11 | 12 | 13 | 14 | YES 15 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 16 | 17 | 18 | YES 19 | 20 | IBFilesOwner 21 | 22 | 23 | IBFirstResponder 24 | 25 | 26 | 27 | 274 28 | {320, 460} 29 | 30 | 31 | 3 32 | MC43NQA 33 | 34 | 2 35 | 36 | 37 | NO 38 | 39 | 40 | 41 | 42 | 43 | YES 44 | 45 | 46 | view 47 | 48 | 49 | 50 | 7 51 | 52 | 53 | 54 | 55 | YES 56 | 57 | 0 58 | 59 | YES 60 | 61 | 62 | 63 | 64 | 65 | -1 66 | 67 | 68 | RmlsZSdzIE93bmVyA 69 | 70 | 71 | -2 72 | 73 | 74 | 75 | 76 | 6 77 | 78 | 79 | 80 | 81 | 82 | 83 | YES 84 | 85 | YES 86 | -1.CustomClassName 87 | -2.CustomClassName 88 | 6.IBEditorWindowLastContentRect 89 | 6.IBPluginDependency 90 | 91 | 92 | YES 93 | MixTwoAudioFilesDemoViewController 94 | UIResponder 95 | {{438, 347}, {320, 480}} 96 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 97 | 98 | 99 | 100 | YES 101 | 102 | YES 103 | 104 | 105 | YES 106 | 107 | 108 | 109 | 110 | YES 111 | 112 | YES 113 | 114 | 115 | YES 116 | 117 | 118 | 119 | 7 120 | 121 | 122 | 123 | YES 124 | 125 | MixTwoAudioFilesDemoViewController 126 | UIViewController 127 | 128 | IBProjectSource 129 | Classes/MixTwoAudioFilesDemoViewController.h 130 | 131 | 132 | 133 | 134 | 0 135 | MixTwoAudioFilesDemo.xcodeproj 136 | 3 137 | 138 | 139 | -------------------------------------------------------------------------------- /MixTwoAudioFilesDemo_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'MixTwoAudioFilesDemo' target in the 'MixTwoAudioFilesDemo' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a pcm audio mixing demo for the iPhone, open up this xcode project 2 | in the simulator and run it to hear the results of two mixed audio tracks. 3 | Mixing two tracks before playing them is much better than using two 4 | AVAudioPlayer objects because mixing actually keeps two audio tracks in sync. 5 | The example sounds are a drum kit and a violin with lots of reverb. 6 | 7 | -------------------------------------------------------------------------------- /funk.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpsim/Mix2Files/ac2670e4323db275da0433a93e73b73a576f75f4/funk.mp3 -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MixTwoAudioFilesDemo 4 | // 5 | // Created by Moses DeJong on 3/25/09. 6 | // Copyright __MyCompanyName__ 2009. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) { 12 | 13 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | [pool release]; 16 | return retVal; 17 | } 18 | -------------------------------------------------------------------------------- /tk.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpsim/Mix2Files/ac2670e4323db275da0433a93e73b73a576f75f4/tk.mp3 -------------------------------------------------------------------------------- /toms.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpsim/Mix2Files/ac2670e4323db275da0433a93e73b73a576f75f4/toms.mp3 --------------------------------------------------------------------------------