mirror of
https://github.com/thes3m/XNI
synced 2024-12-26 13:26:06 +01:00
Audio support added
git-svn-id: http://xni.googlecode.com/svn/XNI@50 ac433895-eea3-a490-d80a-17149a75e588
This commit is contained in:
parent
2f0bc9f91a
commit
1ca44f0f04
23
Classes/Retronator/Xni/Framework/Audio/AudioEnums.h
Normal file
23
Classes/Retronator/Xni/Framework/Audio/AudioEnums.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#import <OpenAL/al.h>
|
||||||
|
#import <OpenAL/alc.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AudioChannelsMono = AL_FORMAT_MONO16,
|
||||||
|
AudioChannelsStereo = AL_FORMAT_STEREO16
|
||||||
|
} AudioChannels;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AudioStopOptionsAsAuthored,
|
||||||
|
AudioStopOptionsImmediate
|
||||||
|
} AudioStopOptions;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MicrophoneStateStarted,
|
||||||
|
MicrophoneStateStopped
|
||||||
|
} MicrophoneState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SoundStatePaused = AL_PAUSED,
|
||||||
|
SoundStatePlaying = AL_PLAYING,
|
||||||
|
SoundStateStopped = AL_STOPPED
|
||||||
|
} SoundState;
|
@ -0,0 +1,3 @@
|
|||||||
|
#import "AudioEnums.h"
|
||||||
|
|
||||||
|
@class SoundEffect, SoundEffectInstance;
|
@ -0,0 +1,4 @@
|
|||||||
|
#import "AudioEnums.h"
|
||||||
|
|
||||||
|
#import "SoundEffect.h"
|
||||||
|
#import "SoundEffectInstance.h"
|
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// SoundEffect+Internal.h
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#import "SoundEffect.h"
|
||||||
|
|
||||||
|
@interface SoundEffect (Internal)
|
||||||
|
|
||||||
|
+ (void) update;
|
||||||
|
|
||||||
|
@end
|
49
Classes/Retronator/Xni/Framework/Audio/SoundEffect.h
Normal file
49
Classes/Retronator/Xni/Framework/Audio/SoundEffect.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// SoundEffect.h
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <OpenAL/al.h>
|
||||||
|
#import <OpenAL/alc.h>
|
||||||
|
|
||||||
|
#import "Retronator.Xni.Framework.Audio.classes.h"
|
||||||
|
|
||||||
|
@interface SoundEffect : NSObject {
|
||||||
|
@private
|
||||||
|
NSData *buffer;
|
||||||
|
int offset;
|
||||||
|
int count;
|
||||||
|
int sampleRate;
|
||||||
|
AudioChannels channels;
|
||||||
|
int loopStart;
|
||||||
|
int loopLength;
|
||||||
|
NSString *name;
|
||||||
|
|
||||||
|
NSUInteger bufferID;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithBuffer:(NSData*)theBuffer sampleRate:(int)theSampleRate channels:(AudioChannels)theChannels;
|
||||||
|
- (id) initWithBuffer:(NSData*)theBuffer offset:(int)theOffset count:(int)theCount sampleRate:(int)theSampleRate channels:(AudioChannels)theChannels loopStart:(int)theLoopStart loopLength:(int)theLoopLength;
|
||||||
|
|
||||||
|
@property (nonatomic, readonly) NSTimeInterval duration;
|
||||||
|
@property (nonatomic, retain) NSString *name;
|
||||||
|
|
||||||
|
+ (float) speedOfSound;
|
||||||
|
+ (void) setSpeedOfSound:(float)value;
|
||||||
|
|
||||||
|
+ (float) masterVolume;
|
||||||
|
+ (void) setMasterVolume:(float)value;
|
||||||
|
|
||||||
|
+ (SoundEffect*) fromStream:(NSStream*)stream;
|
||||||
|
+ (NSTimeInterval) getSampleDurationForSizeInBytes:(int)sizeInBytes sampleRate:(int)sampleRate channels:(AudioChannels)channels;
|
||||||
|
+ (int) getSampleSizeInBytesForDuration:(NSTimeInterval)duration sampleRate:(int)sampleRate channels:(AudioChannels)channels;
|
||||||
|
|
||||||
|
- (SoundEffectInstance*) createInstance;
|
||||||
|
- (BOOL) play;
|
||||||
|
- (BOOL) playWithVolume:(float)volume pitch:(float)pitch pan:(float)pan;
|
||||||
|
|
||||||
|
@end
|
151
Classes/Retronator/Xni/Framework/Audio/SoundEffect.m
Normal file
151
Classes/Retronator/Xni/Framework/Audio/SoundEffect.m
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
//
|
||||||
|
// SoundEffect.m
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "SoundEffect.h"
|
||||||
|
|
||||||
|
#import "Retronator.Xni.Framework.Audio.h"
|
||||||
|
|
||||||
|
#import "SoundEffectInstance+Internal.h"
|
||||||
|
|
||||||
|
@implementation SoundEffect
|
||||||
|
|
||||||
|
static ALCdevice *audioDevice = nil;
|
||||||
|
static ALCcontext *audioContext = nil;
|
||||||
|
|
||||||
|
static NSMutableArray *playingInstances;
|
||||||
|
|
||||||
|
static float speedOfSound = 343.5;
|
||||||
|
static float masterVolume = 1;
|
||||||
|
|
||||||
|
+ (void) initialize {
|
||||||
|
if (!audioDevice) {
|
||||||
|
// Initialization
|
||||||
|
audioDevice = alcOpenDevice(NULL); // select the "preferred device"
|
||||||
|
if (audioDevice) {
|
||||||
|
// use the device to make a context
|
||||||
|
audioContext=alcCreateContext(audioDevice,NULL);
|
||||||
|
// set my context to the currently active one
|
||||||
|
alcMakeContextCurrent(audioContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
playingInstances = [[NSMutableArray alloc] init];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithBuffer:(NSData*)theBuffer sampleRate:(int)theSampleRate channels:(AudioChannels)theChannels {
|
||||||
|
return [self initWithBuffer:theBuffer offset:0 count:[theBuffer length] sampleRate:theSampleRate channels:theChannels loopStart:0 loopLength:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithBuffer:(NSData*)theBuffer
|
||||||
|
offset:(int)theOffset
|
||||||
|
count:(int)theCount
|
||||||
|
sampleRate:(int)theSampleRate
|
||||||
|
channels:(AudioChannels)theChannels
|
||||||
|
loopStart:(int)theLoopStart
|
||||||
|
loopLength:(int)theLoopLength
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
buffer = theBuffer;
|
||||||
|
offset = theOffset;
|
||||||
|
count = theCount;
|
||||||
|
sampleRate = theSampleRate;
|
||||||
|
channels = theChannels;
|
||||||
|
loopStart = theLoopStart;
|
||||||
|
loopLength = theLoopLength;
|
||||||
|
|
||||||
|
// Create an OpenAL buffer.
|
||||||
|
alGenBuffers(1, &bufferID);
|
||||||
|
alBufferData(bufferID, channels, [theBuffer bytes], [theBuffer length], theSampleRate);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize duration, name;
|
||||||
|
|
||||||
|
+ (float) speedOfSound {
|
||||||
|
return speedOfSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void) setSpeedOfSound:(float)value {
|
||||||
|
speedOfSound = value;
|
||||||
|
alSpeedOfSound(speedOfSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (float) masterVolume {
|
||||||
|
return masterVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void) setMasterVolume:(float)value {
|
||||||
|
masterVolume = value;
|
||||||
|
alListenerf(AL_GAIN, masterVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (SoundEffect*) fromStream:(NSStream*)stream {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (int) getSecondInBytesForSampleRate:(int)sampleRate channels:(AudioChannels)channels {
|
||||||
|
int secondInBytes = sampleRate;
|
||||||
|
|
||||||
|
// 16 bits per sample = 2 bytes per sample.
|
||||||
|
secondInBytes *= 2;
|
||||||
|
|
||||||
|
// Multiply with number of channels.
|
||||||
|
if (channels == AudioChannelsStereo) {
|
||||||
|
secondInBytes *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return secondInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSTimeInterval) getSampleDurationForSizeInBytes:(int)sizeInBytes sampleRate:(int)sampleRate channels:(AudioChannels)channels {
|
||||||
|
return (double)sizeInBytes / (double)[SoundEffect getSecondInBytesForSampleRate:sampleRate channels:channels];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (int) getSampleSizeInBytesForDuration:(NSTimeInterval)duration sampleRate:(int)sampleRate channels:(AudioChannels)channels {
|
||||||
|
return (int)(duration * [SoundEffect getSecondInBytesForSampleRate:sampleRate channels:channels]);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void) update {
|
||||||
|
int i=0;
|
||||||
|
while (i<[playingInstances count]) {
|
||||||
|
SoundEffectInstance *instance = [playingInstances objectAtIndex:i];
|
||||||
|
if (instance.state == SoundStateStopped) {
|
||||||
|
[playingInstances removeObjectAtIndex:i];
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (SoundEffectInstance *) createInstance {
|
||||||
|
return [[[SoundEffectInstance alloc] initWithBufferID:bufferID] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) play {
|
||||||
|
return [self playWithVolume:1 pitch:0 pan:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) playWithVolume:(float)volume pitch:(float)pitch pan:(float)pan {
|
||||||
|
SoundEffectInstance *instance = [self createInstance];
|
||||||
|
[playingInstances addObject:instance];
|
||||||
|
instance.volume = volume;
|
||||||
|
instance.pitch = pitch;
|
||||||
|
instance.pan = pan;
|
||||||
|
[instance play];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
alDeleteBuffers(1, &bufferID);
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// SoundEffectInstance+Internal.h
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
|
||||||
|
@interface SoundEffectInstance (Internal)
|
||||||
|
|
||||||
|
- (id) initWithBufferID:(NSUInteger)bufferID;
|
||||||
|
|
||||||
|
@end
|
32
Classes/Retronator/Xni/Framework/Audio/SoundEffectInstance.h
Normal file
32
Classes/Retronator/Xni/Framework/Audio/SoundEffectInstance.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// SoundEffectInstance.h
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <OpenAL/al.h>
|
||||||
|
#import <OpenAL/alc.h>
|
||||||
|
|
||||||
|
#import "Retronator.Xni.Framework.Audio.classes.h"
|
||||||
|
|
||||||
|
@interface SoundEffectInstance : NSObject {
|
||||||
|
@private
|
||||||
|
BOOL isLooped;
|
||||||
|
float pan, pitch, volume;
|
||||||
|
NSUInteger sourceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (nonatomic) BOOL isLooped;
|
||||||
|
@property (nonatomic, readonly) SoundState state;
|
||||||
|
@property (nonatomic) float pan, pitch, volume;
|
||||||
|
|
||||||
|
- (void) play;
|
||||||
|
- (void) pause;
|
||||||
|
- (void) resume;
|
||||||
|
- (void) stop;
|
||||||
|
- (void) stopImmediate:(BOOL)immediate;
|
||||||
|
|
||||||
|
@end
|
91
Classes/Retronator/Xni/Framework/Audio/SoundEffectInstance.m
Normal file
91
Classes/Retronator/Xni/Framework/Audio/SoundEffectInstance.m
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
//
|
||||||
|
// SoundEffectInstance.m
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "SoundEffectInstance.h"
|
||||||
|
#import "SoundEffectInstance+Internal.h"
|
||||||
|
|
||||||
|
@implementation SoundEffectInstance
|
||||||
|
|
||||||
|
- (id) initWithBufferID:(NSUInteger)bufferID
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
// grab a source ID from openAL
|
||||||
|
alGenSources(1, &sourceID);
|
||||||
|
|
||||||
|
// attach the buffer to the source
|
||||||
|
alSourcei(sourceID, AL_BUFFER, bufferID);
|
||||||
|
|
||||||
|
// set some basic source prefs
|
||||||
|
alSourcef(sourceID, AL_PITCH, 1.0f);
|
||||||
|
alSourcef(sourceID, AL_GAIN, 1.0f);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize isLooped, pan, pitch, volume;
|
||||||
|
|
||||||
|
- (void) setIsLooped:(BOOL)value {
|
||||||
|
isLooped = value;
|
||||||
|
alSourcei(sourceID, AL_LOOPING, isLooped);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (SoundState) state {
|
||||||
|
ALenum state;
|
||||||
|
alGetSourcei(sourceID, AL_SOURCE_STATE, &state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setPan:(float)value {
|
||||||
|
pan = value;
|
||||||
|
alSource3f(sourceID, AL_POSITION, pan, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setPitch:(float)value {
|
||||||
|
pitch = value;
|
||||||
|
float alPitch = pow(2, value);
|
||||||
|
alSourcef(sourceID, AL_PITCH, alPitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setVolume:(float)value {
|
||||||
|
volume = value;
|
||||||
|
alSourcef(sourceID, AL_GAIN, volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) play {
|
||||||
|
alSourcePlay(sourceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void) pause {
|
||||||
|
alSourcePause(sourceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void) resume {
|
||||||
|
alSourcePlay(sourceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) stop {
|
||||||
|
[self stopImmediate:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) stopImmediate:(BOOL)immediate {
|
||||||
|
if (immediate) {
|
||||||
|
alSourceStop(sourceID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
alDeleteSources(1, &sourceID);
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// AudioContent.h
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "Retronator.Xni.Framework.Content.Pipeline.Audio.classes.h"
|
||||||
|
|
||||||
|
#import "ContentItem.h"
|
||||||
|
|
||||||
|
@interface AudioContent : ContentItem {
|
||||||
|
NSTimeInterval duration;
|
||||||
|
NSString *fileName;
|
||||||
|
AudioFileType fileType;
|
||||||
|
AudioFormat *format;
|
||||||
|
int loopLength;
|
||||||
|
int loopStart;
|
||||||
|
|
||||||
|
@private
|
||||||
|
NSURL *fileUrl;
|
||||||
|
ExtAudioFileRef extRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithAudioFileName:(NSString*)theFileName audioFileType:(AudioFileType)theFileType;
|
||||||
|
|
||||||
|
@property (nonatomic, readonly) NSData *data;
|
||||||
|
@property (nonatomic, readonly) NSTimeInterval duration;
|
||||||
|
@property (nonatomic, readonly) NSString *fileName;
|
||||||
|
@property (nonatomic, readonly) AudioFileType fileType;
|
||||||
|
@property (nonatomic, readonly) AudioFormat *format;
|
||||||
|
@property (nonatomic, readonly) int loopLength;
|
||||||
|
@property (nonatomic, readonly) int loopStart;
|
||||||
|
|
||||||
|
- (void) convertFormatTo:(ConversionFormat)formatType quality:(ConversionQuality)quality targetFileName:(NSString*)targetFileName;
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,119 @@
|
|||||||
|
//
|
||||||
|
// AudioContent.m
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AudioContent.h"
|
||||||
|
|
||||||
|
#import "Retronator.Xni.Framework.Content.Pipeline.Audio.h"
|
||||||
|
|
||||||
|
@implementation AudioContent
|
||||||
|
|
||||||
|
- (id) initWithAudioFileName:(NSString *)theFileName audioFileType:(AudioFileType)theFileType
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
fileName = theFileName;
|
||||||
|
fileType = theFileType;
|
||||||
|
|
||||||
|
// Load file.
|
||||||
|
OSStatus err = noErr;
|
||||||
|
AudioStreamBasicDescription theFileFormat;
|
||||||
|
UInt32 thePropertySize = sizeof(theFileFormat);
|
||||||
|
|
||||||
|
// Open a file with ExtAudioFileOpen().
|
||||||
|
fileUrl = [[NSURL fileURLWithPath:theFileName] retain];
|
||||||
|
extRef = nil;
|
||||||
|
err = ExtAudioFileOpenURL((CFURLRef)fileUrl, &extRef);
|
||||||
|
if (err) {
|
||||||
|
[NSException raise:@"NotSupportedException" format:@"ExtAudioFileOpenURL FAILED, Error = %ld\n", err];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the audio data format.
|
||||||
|
err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat);
|
||||||
|
if (err) {
|
||||||
|
[NSException raise:@"NotSupportedException" format:@"ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %ld\n", err];
|
||||||
|
}
|
||||||
|
|
||||||
|
format = [[AudioFormat alloc] initWithDescription:theFileFormat];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize duration, fileName, fileType, format, loopLength, loopStart;
|
||||||
|
|
||||||
|
- (NSData *) data {
|
||||||
|
// Get the total frame count
|
||||||
|
void* theData = NULL;
|
||||||
|
SInt64 theFileLengthInFrames = 0;
|
||||||
|
UInt32 thePropertySize = sizeof(theFileLengthInFrames);
|
||||||
|
OSStatus err = noErr;
|
||||||
|
err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames);
|
||||||
|
if (err) {
|
||||||
|
[NSException raise:@"NotSupportedException" format:@"MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %ld\n", err];
|
||||||
|
}
|
||||||
|
|
||||||
|
duration = (double)theFileLengthInFrames / (double)format.sampleRate;
|
||||||
|
|
||||||
|
// Read all the data into memory
|
||||||
|
UInt32 dataSize = theFileLengthInFrames * format.nativeWaveFormat.mBytesPerFrame;
|
||||||
|
|
||||||
|
theData = malloc(dataSize);
|
||||||
|
if (theData)
|
||||||
|
{
|
||||||
|
AudioBufferList theDataBuffer;
|
||||||
|
theDataBuffer.mNumberBuffers = 1;
|
||||||
|
theDataBuffer.mBuffers[0].mDataByteSize = dataSize;
|
||||||
|
theDataBuffer.mBuffers[0].mNumberChannels = format.nativeWaveFormat.mChannelsPerFrame;
|
||||||
|
theDataBuffer.mBuffers[0].mData = theData;
|
||||||
|
|
||||||
|
// Read the data into an AudioBufferList
|
||||||
|
err = ExtAudioFileRead(extRef, (UInt32*)&theFileLengthInFrames, &theDataBuffer);
|
||||||
|
if (err) {
|
||||||
|
// failure
|
||||||
|
[NSException raise:@"NotSupportedException" format:@"MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", err];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NSData *result = [NSData dataWithBytes:theData length:dataSize];
|
||||||
|
free(theData);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) convertFormatTo:(ConversionFormat)formatType quality:(ConversionQuality)quality targetFileName:(NSString *)targetFileName {
|
||||||
|
AudioStreamBasicDescription theOutputFormat;
|
||||||
|
|
||||||
|
// Set the client format to 16 bit signed integer (native-endian) data
|
||||||
|
// Maintain the channel count and sample rate of the original source format
|
||||||
|
theOutputFormat.mSampleRate = format.nativeWaveFormat.mSampleRate;
|
||||||
|
theOutputFormat.mChannelsPerFrame = format.nativeWaveFormat.mChannelsPerFrame;
|
||||||
|
|
||||||
|
theOutputFormat.mFormatID = formatType;
|
||||||
|
theOutputFormat.mBytesPerPacket = 2 * theOutputFormat.mChannelsPerFrame;
|
||||||
|
theOutputFormat.mFramesPerPacket = 1;
|
||||||
|
theOutputFormat.mBytesPerFrame = 2 * theOutputFormat.mChannelsPerFrame;
|
||||||
|
theOutputFormat.mBitsPerChannel = 16;
|
||||||
|
theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
|
||||||
|
|
||||||
|
// Set the desired client (output) data format
|
||||||
|
OSStatus err = noErr;
|
||||||
|
err = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(theOutputFormat), &theOutputFormat);
|
||||||
|
if (err) {
|
||||||
|
[NSException raise:@"NotSupportedException" format:@"MyGetOpenALAudioData: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) FAILED, Error = %ld\n", err];
|
||||||
|
}
|
||||||
|
|
||||||
|
[format release];
|
||||||
|
format = [[AudioFormat alloc] initWithDescription:theOutputFormat];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
//if (extRef) ExtAudioFileDispose(extRef);
|
||||||
|
[fileUrl release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,20 @@
|
|||||||
|
#import <AudioToolbox/AudioToolbox.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AudioFileTypeMp3,
|
||||||
|
AudioFileTypeWav,
|
||||||
|
// AudioFileTypeWma,
|
||||||
|
} AudioFileType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ConversionFormatAdpcm = kAudioFormatAppleIMA4,
|
||||||
|
ConversionFormatPcm = kAudioFormatLinearPCM,
|
||||||
|
// ConversionFormatWindowsMedia,
|
||||||
|
// ConversionFormatXma,
|
||||||
|
} ConversionFormat;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ConversionQualityLow,
|
||||||
|
ConversionQualityMedium,
|
||||||
|
ConversionQualityBest,
|
||||||
|
} ConversionQuality;
|
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// AudioFormat.h
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import <AudioToolbox/AudioToolbox.h>
|
||||||
|
|
||||||
|
@interface AudioFormat : NSObject {
|
||||||
|
int averageBytesPerSecond;
|
||||||
|
int bitsPerSample;
|
||||||
|
int blockAlign;
|
||||||
|
int channelCount;
|
||||||
|
int format;
|
||||||
|
AudioStreamBasicDescription nativeWaveFormat;
|
||||||
|
int sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithDescription:(AudioStreamBasicDescription)description;
|
||||||
|
|
||||||
|
@property (nonatomic, readonly) int averageBytesPerSecond;
|
||||||
|
@property (nonatomic, readonly) int bitsPerSample;
|
||||||
|
@property (nonatomic, readonly) int blockAlign;
|
||||||
|
@property (nonatomic, readonly) int channelCount;
|
||||||
|
@property (nonatomic, readonly) int format;
|
||||||
|
@property (nonatomic, readonly) AudioStreamBasicDescription nativeWaveFormat;
|
||||||
|
@property (nonatomic, readonly) int sampleRate;
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// AudioFormat.m
|
||||||
|
// XNI
|
||||||
|
//
|
||||||
|
// Created by Matej Jan on 15.12.10.
|
||||||
|
// Copyright 2010 Retronator. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AudioFormat.h"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation AudioFormat
|
||||||
|
|
||||||
|
- (id) initWithDescription:(AudioStreamBasicDescription)description {
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
averageBytesPerSecond = description.mSampleRate * description.mBytesPerFrame;
|
||||||
|
bitsPerSample = description.mBitsPerChannel;
|
||||||
|
blockAlign = description.mBytesPerFrame;
|
||||||
|
channelCount = description.mChannelsPerFrame;
|
||||||
|
format = description.mFormatID;
|
||||||
|
nativeWaveFormat = description;
|
||||||
|
sampleRate = description.mSampleRate;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize averageBytesPerSecond, bitsPerSample, blockAlign, channelCount, format, nativeWaveFormat, sampleRate;
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,3 @@
|
|||||||
|
#import "AudioContentEnums.h"
|
||||||
|
|
||||||
|
@class AudioContent, AudioFormat;
|
@ -0,0 +1,4 @@
|
|||||||
|
#import "AudioContentEnums.h"
|
||||||
|
|
||||||
|
#import "AudioContent.h"
|
||||||
|
#import "AudioFormat.h"
|
Loading…
x
Reference in New Issue
Block a user