mirror of
https://github.com/id-Software/DOOM-IOS2.git
synced 2026-03-19 16:39:26 +01:00
Initial Commit
This commit is contained in:
102
common/SDL_shim/SDL_Mixer.h
Executable file
102
common/SDL_shim/SDL_Mixer.h
Executable file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
|
||||
Copyright (C) 2011 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef doomengine_SDL_Mixer_h
|
||||
#define doomengine_SDL_Mixer_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
===============================
|
||||
|
||||
This is a minimal implemenation of SDL_Mixer for iOS, just to get MIDI files
|
||||
playing so that we can play the music directly from the WADs.
|
||||
|
||||
===============================
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct Mix_Music_tag {
|
||||
char unused;
|
||||
} Mix_Music;
|
||||
|
||||
|
||||
/* Open the mixer with a certain audio format */
|
||||
extern int Mix_OpenAudio(int frequency, uint16_t format, int channels,
|
||||
int chunksize);
|
||||
|
||||
|
||||
/* Close the mixer, halting all playing audio */
|
||||
extern void Mix_CloseAudio(void);
|
||||
|
||||
|
||||
/* Set a function that is called after all mixing is performed.
|
||||
This can be used to provide real-time visual display of the audio stream
|
||||
or add a custom mixer filter for the stream data.
|
||||
*/
|
||||
extern void Mix_SetPostMix(void (*mix_func)
|
||||
(void *udata, uint8_t *stream, int len), void *arg);
|
||||
|
||||
|
||||
/* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */
|
||||
extern int Mix_FadeInMusic(Mix_Music *music, int loops, int ms);
|
||||
|
||||
|
||||
/* Pause/Resume the music stream */
|
||||
extern void Mix_PauseMusic(void);
|
||||
extern void Mix_ResumeMusic(void);
|
||||
|
||||
|
||||
/* Halt a channel, fading it out progressively till it's silent
|
||||
The ms parameter indicates the number of milliseconds the fading
|
||||
will take.
|
||||
*/
|
||||
extern int Mix_FadeOutMusic(int ms);
|
||||
|
||||
|
||||
/* Free an audio chunk previously loaded */
|
||||
extern void Mix_FreeMusic(Mix_Music *music);
|
||||
|
||||
|
||||
/* Load a wave file or a music (.mod .s3m .it .xm) file */
|
||||
extern Mix_Music * Mix_LoadMUS(const char *file);
|
||||
|
||||
|
||||
extern const char * Mix_GetError(void);
|
||||
|
||||
|
||||
|
||||
|
||||
/* Set the volume in the range of 0-128 of a specific channel or chunk.
|
||||
If the specified channel is -1, set volume for all channels.
|
||||
Returns the original volume.
|
||||
If the specified volume is -1, just return the current volume.
|
||||
*/
|
||||
extern int Mix_VolumeMusic(int volume);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
517
common/SDL_shim/ios/SDL_Mixer.m
Executable file
517
common/SDL_shim/ios/SDL_Mixer.m
Executable file
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
|
||||
Copyright (C) 2011 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
===============================
|
||||
|
||||
iOS implementation of our SDL_Mixer shim for playing MIDI files.
|
||||
|
||||
===============================
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "SDL_Mixer.h"
|
||||
|
||||
|
||||
// Use the Embedded Audio Synthesis library as the backend MIDI renderer.
|
||||
#include "embeddedaudiosynthesis/EASGlue.h"
|
||||
|
||||
|
||||
// Use Core Audio Units for sound output on the device.
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
|
||||
/*
|
||||
===============================
|
||||
|
||||
"Constants"
|
||||
|
||||
===============================
|
||||
*/
|
||||
#define ID_GRAPH_SAMPLE_RATE 22050
|
||||
|
||||
|
||||
/*
|
||||
===============================
|
||||
|
||||
Internal Structures
|
||||
|
||||
===============================
|
||||
*/
|
||||
|
||||
// Data structure for mono or stereo sound, to pass to the application's render callback function,
|
||||
// which gets invoked by a Mixer unit input bus when it needs more audio to play.
|
||||
typedef struct {
|
||||
|
||||
BOOL isStereo; // set to true if there is data in the audioDataRight member
|
||||
UInt32 frameCount; // the total number of frames in the audio data
|
||||
UInt32 sampleNumber; // the next audio sample to play
|
||||
} soundStruct, *soundStructPtr;
|
||||
|
||||
|
||||
|
||||
typedef struct MIDIPlayerGraph_tag {
|
||||
|
||||
AUGraph processingGraph;
|
||||
AudioUnit ioUnit;
|
||||
BOOL playing;
|
||||
|
||||
AudioStreamBasicDescription streamFormat;
|
||||
|
||||
soundStruct soundStructInst;
|
||||
} MIDIPlayerGraph;
|
||||
|
||||
static MIDIPlayerGraph midiPlayer;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============================
|
||||
|
||||
Internal prototypes
|
||||
|
||||
===============================
|
||||
*/
|
||||
AudioStreamBasicDescription getStreamFormat( void );
|
||||
static void printASBD( AudioStreamBasicDescription asbd );
|
||||
static void printErrorMessage( NSString * errorString, OSStatus result );
|
||||
static void configureAndInitializeAudioProcessingGraph( MIDIPlayerGraph * player );
|
||||
static void startMIDIPlayer( MIDIPlayerGraph * player );
|
||||
|
||||
// AU graph callback.
|
||||
static OSStatus inputRenderCallback (
|
||||
|
||||
void *inRefCon, // A pointer to a struct containing the complete audio data
|
||||
// to play, as well as state information such as the
|
||||
// first sample to play on this invocation of the callback.
|
||||
AudioUnitRenderActionFlags *ioActionFlags, // Unused here. When generating audio, use ioActionFlags to indicate silence
|
||||
// between sounds; for silence, also memset the ioData buffers to 0.
|
||||
const AudioTimeStamp *inTimeStamp, // Unused here.
|
||||
UInt32 inBusNumber, // The mixer unit input bus that is requesting some new
|
||||
// frames of audio data to play.
|
||||
UInt32 inNumberFrames, // The number of frames of audio to provide to the buffer(s)
|
||||
// pointed to by the ioData parameter.
|
||||
AudioBufferList *ioData // On output, the audio data to play. The callback's primary
|
||||
// responsibility is to fill the buffer(s) in the
|
||||
// AudioBufferList.
|
||||
);
|
||||
|
||||
|
||||
|
||||
/* Open the mixer with a certain audio format */
|
||||
int Mix_OpenAudio(int frequency, uint16_t format, int channels,
|
||||
int chunksize) {
|
||||
|
||||
EASGlueInit();
|
||||
|
||||
midiPlayer.streamFormat = getStreamFormat();
|
||||
midiPlayer.playing = FALSE;
|
||||
|
||||
configureAndInitializeAudioProcessingGraph( &midiPlayer );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Close the mixer, halting all playing audio */
|
||||
void Mix_CloseAudio(void) {
|
||||
AUGraphStop( midiPlayer.processingGraph );
|
||||
EASGlueShutdown();
|
||||
}
|
||||
|
||||
|
||||
/* Set a function that is called after all mixing is performed.
|
||||
This can be used to provide real-time visual display of the audio stream
|
||||
or add a custom mixer filter for the stream data.
|
||||
*/
|
||||
void Mix_SetPostMix(void (*mix_func)
|
||||
(void *udata, uint8_t *stream, int len), void *arg) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */
|
||||
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms) {
|
||||
|
||||
|
||||
startMIDIPlayer( &midiPlayer );
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Pause/Resume the music stream */
|
||||
void Mix_PauseMusic(void) {
|
||||
EASGluePause();
|
||||
}
|
||||
|
||||
|
||||
void Mix_ResumeMusic(void) {
|
||||
EASGlueResume();
|
||||
}
|
||||
|
||||
|
||||
/* Halt a channel, fading it out progressively till it's silent
|
||||
The ms parameter indicates the number of milliseconds the fading
|
||||
will take.
|
||||
*/
|
||||
int Mix_FadeOutMusic(int ms) {
|
||||
|
||||
EASGlueCloseFile();
|
||||
|
||||
AUGraphStop( midiPlayer.processingGraph );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Free an audio chunk previously loaded */
|
||||
void Mix_FreeMusic(Mix_Music *music) {
|
||||
free(music);
|
||||
}
|
||||
|
||||
|
||||
/* Load a wave file or a music (.mod .s3m .it .xm) file */
|
||||
Mix_Music * Mix_LoadMUS(const char *file) {
|
||||
|
||||
EASGlueOpenFile( file );
|
||||
|
||||
Mix_Music * musicStruct = malloc( sizeof(Mix_Music) );
|
||||
|
||||
return musicStruct;
|
||||
}
|
||||
|
||||
|
||||
const char * Mix_GetError(void) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/* Set the volume in the range of 0-128 of a specific channel or chunk.
|
||||
If the specified channel is -1, set volume for all channels.
|
||||
Returns the original volume.
|
||||
If the specified volume is -1, just return the current volume.
|
||||
*/
|
||||
int Mix_VolumeMusic(int volume) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=================================
|
||||
Audio Unit helper functions
|
||||
=================================
|
||||
*/
|
||||
|
||||
|
||||
AudioStreamBasicDescription getStreamFormat( void ) {
|
||||
|
||||
AudioStreamBasicDescription streamFormat = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
// The AudioUnitSampleType data type is the recommended type for sample data in audio
|
||||
// units. This obtains the byte size of the type for use in filling in the ASBD.
|
||||
size_t bytesPerSample = sizeof (AudioUnitSampleType);
|
||||
|
||||
// Fill the application audio format struct's fields to define a linear PCM,
|
||||
// stereo, noninterleaved stream at the hardware sample rate.
|
||||
streamFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
streamFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
|
||||
streamFormat.mBytesPerPacket = bytesPerSample;
|
||||
streamFormat.mFramesPerPacket = 1;
|
||||
streamFormat.mBytesPerFrame = bytesPerSample;
|
||||
streamFormat.mChannelsPerFrame = 2; // 2 indicates stereo
|
||||
streamFormat.mBitsPerChannel = 8 * bytesPerSample;
|
||||
streamFormat.mSampleRate = ID_GRAPH_SAMPLE_RATE;
|
||||
|
||||
|
||||
NSLog (@"The stereo stream format for the I/O unit:");
|
||||
printASBD( streamFormat );
|
||||
|
||||
return streamFormat;
|
||||
}
|
||||
|
||||
static void startMIDIPlayer( MIDIPlayerGraph * player ) {
|
||||
|
||||
if ( player == 0 ) {
|
||||
NSLog( @"NULL player object, can't start!" );
|
||||
return;
|
||||
}
|
||||
|
||||
NSLog (@"Starting audio processing graph");
|
||||
OSStatus result = AUGraphStart (player->processingGraph);
|
||||
if (noErr != result) { printErrorMessage( @"AUGraphStart", result ); return;}
|
||||
|
||||
player->playing = YES;
|
||||
|
||||
}
|
||||
|
||||
// You can use this method during development and debugging to look at the
|
||||
// fields of an AudioStreamBasicDescription struct.
|
||||
static void printASBD( AudioStreamBasicDescription asbd ) {
|
||||
|
||||
char formatIDString[5];
|
||||
UInt32 formatID = CFSwapInt32HostToBig (asbd.mFormatID);
|
||||
bcopy (&formatID, formatIDString, 4);
|
||||
formatIDString[4] = '\0';
|
||||
|
||||
NSLog (@" Sample Rate: %10.0f", asbd.mSampleRate);
|
||||
NSLog (@" Format ID: %10s", formatIDString);
|
||||
NSLog (@" Format Flags: %10lX", asbd.mFormatFlags);
|
||||
NSLog (@" Bytes per Packet: %10lu", asbd.mBytesPerPacket);
|
||||
NSLog (@" Frames per Packet: %10lu", asbd.mFramesPerPacket);
|
||||
NSLog (@" Bytes per Frame: %10lu", asbd.mBytesPerFrame);
|
||||
NSLog (@" Channels per Frame: %10lu", asbd.mChannelsPerFrame);
|
||||
NSLog (@" Bits per Channel: %10lu", asbd.mBitsPerChannel);
|
||||
}
|
||||
|
||||
|
||||
static void printErrorMessage( NSString * errorString, OSStatus result ) {
|
||||
|
||||
char resultString[5];
|
||||
UInt32 swappedResult = CFSwapInt32HostToBig (result);
|
||||
bcopy (&swappedResult, resultString, 4);
|
||||
resultString[4] = '\0';
|
||||
|
||||
NSLog (
|
||||
@"*** %@ error: %s\n",
|
||||
errorString,
|
||||
(char*) &resultString
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// This method performs all the work needed to set up the audio processing graph:
|
||||
|
||||
// 1. Instantiate and open an audio processing graph
|
||||
// 2. Obtain the audio unit nodes for the graph
|
||||
// 3. Configure the Multichannel Mixer unit
|
||||
// * specify the number of input buses
|
||||
// * specify the output sample rate
|
||||
// * specify the maximum frames-per-slice
|
||||
// 4. Initialize the audio processing graph
|
||||
|
||||
static void configureAndInitializeAudioProcessingGraph( MIDIPlayerGraph * player ) {
|
||||
|
||||
if ( player == 0 ) {
|
||||
NSLog( @"NULL player graph object, can't initialize it!" );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
NSLog (@"Configuring and then initializing audio processing graph");
|
||||
OSStatus result = noErr;
|
||||
|
||||
//............................................................................
|
||||
// Create a new audio processing graph.
|
||||
result = NewAUGraph (&player->processingGraph);
|
||||
|
||||
if (noErr != result) { printErrorMessage( @"NewAUGraph", result ); return;}
|
||||
|
||||
|
||||
//............................................................................
|
||||
// Specify the audio unit component descriptions for the audio units to be
|
||||
// added to the graph.
|
||||
|
||||
// I/O unit
|
||||
AudioComponentDescription iOUnitDescription;
|
||||
iOUnitDescription.componentType = kAudioUnitType_Output;
|
||||
iOUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
iOUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
iOUnitDescription.componentFlags = 0;
|
||||
iOUnitDescription.componentFlagsMask = 0;
|
||||
|
||||
|
||||
//............................................................................
|
||||
// Add nodes to the audio processing graph.
|
||||
NSLog (@"Adding nodes to audio processing graph");
|
||||
|
||||
AUNode iONode; // node for I/O unit
|
||||
|
||||
// Add the nodes to the audio processing graph
|
||||
result = AUGraphAddNode (
|
||||
player->processingGraph,
|
||||
&iOUnitDescription,
|
||||
&iONode);
|
||||
|
||||
if (noErr != result) { printErrorMessage( @"AUGraphNewNode failed for I/O unit", result ); return;}
|
||||
|
||||
//............................................................................
|
||||
// Open the audio processing graph
|
||||
|
||||
// Following this call, the audio units are instantiated but not initialized
|
||||
// (no resource allocation occurs and the audio units are not in a state to
|
||||
// process audio).
|
||||
result = AUGraphOpen (player->processingGraph);
|
||||
|
||||
if (noErr != result) { printErrorMessage( @"AUGraphOpen", result ); return;}
|
||||
|
||||
|
||||
//............................................................................
|
||||
// Obtain the mixer unit instance from its corresponding node.
|
||||
|
||||
result = AUGraphNodeInfo (
|
||||
player->processingGraph,
|
||||
iONode,
|
||||
NULL,
|
||||
&player->ioUnit
|
||||
);
|
||||
|
||||
if (noErr != result) { printErrorMessage( @"AUGraphNodeInfo", result ); return;}
|
||||
|
||||
|
||||
//............................................................................
|
||||
// Multichannel Mixer unit Setup
|
||||
|
||||
|
||||
// Setup the struture that contains the input render callback
|
||||
AURenderCallbackStruct inputCallbackStruct;
|
||||
inputCallbackStruct.inputProc = &inputRenderCallback;
|
||||
inputCallbackStruct.inputProcRefCon = &player->soundStructInst;
|
||||
|
||||
NSLog (@"Registering the render callback with the I/O unit" );
|
||||
// Set a callback for the specified node's specified input
|
||||
result = AUGraphSetNodeInputCallback (
|
||||
player->processingGraph,
|
||||
iONode,
|
||||
0,
|
||||
&inputCallbackStruct
|
||||
);
|
||||
|
||||
if (noErr != result) { printErrorMessage( @"AUGraphSetNodeInputCallback", result ); return;}
|
||||
|
||||
|
||||
NSLog (@"Setting stereo stream format for I/O unit input bus");
|
||||
result = AudioUnitSetProperty (
|
||||
player->ioUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&player->streamFormat,
|
||||
sizeof (player->streamFormat)
|
||||
);
|
||||
|
||||
if (noErr != result) { printErrorMessage( @"AudioUnitSetProperty (set input bus stream format)", result ); return;}
|
||||
|
||||
//............................................................................
|
||||
// Initialize audio processing graph
|
||||
|
||||
// Diagnostic code
|
||||
// Call CAShow if you want to look at the state of the audio processing
|
||||
// graph.
|
||||
NSLog (@"Audio processing graph state immediately before initializing it:");
|
||||
CAShow (player->processingGraph);
|
||||
|
||||
NSLog (@"Initializing the audio processing graph");
|
||||
// Initialize the audio processing graph, configure audio data stream formats for
|
||||
// each input and output, and validate the connections between audio units.
|
||||
result = AUGraphInitialize (player->processingGraph);
|
||||
|
||||
if (noErr != result) { printErrorMessage( @"AUGraphInitialize", result ); return;}
|
||||
}
|
||||
|
||||
#define RAW_EAS_BUFFER_FRAMES 128
|
||||
|
||||
static OSStatus inputRenderCallback (
|
||||
|
||||
void *inRefCon, // A pointer to a struct containing the complete audio data
|
||||
// to play, as well as state information such as the
|
||||
// first sample to play on this invocation of the callback.
|
||||
AudioUnitRenderActionFlags *ioActionFlags, // Unused here. When generating audio, use ioActionFlags to indicate silence
|
||||
// between sounds; for silence, also memset the ioData buffers to 0.
|
||||
const AudioTimeStamp *inTimeStamp, // Unused here.
|
||||
UInt32 inBusNumber, // The mixer unit input bus that is requesting some new
|
||||
// frames of audio data to play.
|
||||
UInt32 inNumberFrames, // The number of frames of audio to provide to the buffer(s)
|
||||
// pointed to by the ioData parameter.
|
||||
AudioBufferList *ioData // On output, the audio data to play. The callback's primary
|
||||
// responsibility is to fill the buffer(s) in the
|
||||
// AudioBufferList.
|
||||
) {
|
||||
|
||||
//printf( "Need %lu samples in %lu buffers!\n", inNumberFrames, ioData->mNumberBuffers );
|
||||
|
||||
EAS_I32 generatedThisRender = 0;
|
||||
EAS_I32 totalGenerated = 0;
|
||||
|
||||
// It looks like EAS interleaves stereo samples, so we have to separate them into the two
|
||||
// different buffers that the audio unit provides.
|
||||
//const UInt32 totalInterleavedSamplesNeeded = inNumberFrames * 2;
|
||||
|
||||
AudioBuffer * audioBufferLeft = &ioData->mBuffers[0];
|
||||
AudioBuffer * audioBufferRight = &ioData->mBuffers[1];
|
||||
|
||||
/*
|
||||
printf( "Need %lu samples in %lu buffers!\n"
|
||||
"audioBuffer byte size: %lu channels: %lu\n",
|
||||
inNumberFrames, ioData->mNumberBuffers,
|
||||
audioBuffer->mDataByteSize, audioBuffer->mNumberChannels );
|
||||
*/
|
||||
AudioUnitSampleType * hardwareBufferLeft = (AudioUnitSampleType *) audioBufferLeft->mData;
|
||||
AudioUnitSampleType * hardwareBufferRight = (AudioUnitSampleType *) audioBufferRight->mData;
|
||||
|
||||
|
||||
// EAS_Render always produces BUFFER_SIZE_IN_MONO_SAMPLES frames per call. Currently, this
|
||||
// is defined to 128. Let's fill up a 128 frame buffer, then do a conversion from EAS_PCM
|
||||
// (which is signed 16-bit integer) to AudioUnitSampleType (which is 8.24 fixed-point with
|
||||
// a range of -1 to +1).
|
||||
//
|
||||
// Note that EAS renders interleaved stereo, so we actually a buffer size of
|
||||
// 2 * BUFFER_SIZE_IN_MONO_SAMPLES.
|
||||
|
||||
EAS_PCM rawEASSamples[RAW_EAS_BUFFER_FRAMES * 2];
|
||||
|
||||
|
||||
// EAS generates interleaved stereo samples, but the AudioUnit wants noninterleaved.
|
||||
while ( totalGenerated < inNumberFrames ) {
|
||||
//EASGlueRender( hardwareBuffer + totalGenerated*2, &generatedThisRender );
|
||||
EASGlueRender( rawEASSamples, &generatedThisRender );
|
||||
|
||||
|
||||
// Convert from EAS's signed 16-bit format to the AudioUnit's 8.24 fixed-point format.
|
||||
// Couldn't find this in the Apple docs, but the 8.24 format should be in the range of
|
||||
// -1.0 to 1.0, wasting 6 bits of precision.
|
||||
// All we have to do here is left-shift by 9 bits. This will not overflow, because the
|
||||
// destination is a 32-bit value.
|
||||
// Also take this opportunity to de-interleave the EAS-rendered samples.
|
||||
for ( int i = 0; i < RAW_EAS_BUFFER_FRAMES; ++i ) {
|
||||
hardwareBufferLeft[totalGenerated + i] = rawEASSamples[i * 2 + 0] << 9;
|
||||
hardwareBufferRight[totalGenerated + i] = rawEASSamples[i * 2 + 1] << 9;
|
||||
}
|
||||
|
||||
totalGenerated += generatedThisRender;
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user