Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
audioCallbacks.iOS.cpp
Go to the documentation of this file.
1 #ifdef PLATFORM_IOS
2 
3 #include <AudioUnit/AudioUnit.h>
4 #include <algorithm>
5 #include <map>
6 #include <new>
7 
8 struct AudioDataRenderer
9 {
10  int LoopStartPoint;
11  int LoopEndPoint;
12  int NumberOfLoops;
13  bool IsInfiniteLoop;
14 
15  int CurrentFrame;
16  int TotalNumberOfFrames;
17 
18  int NumberOfChannels;
19  char* AudioDataBuffer;
20 
21  bool IsEnabled2D;
22  bool IsEnabled3D;
23 
24  bool PlaybackEnded;
25 
26  void* HandleChannelMixer;
27  void* Handle3DMixer;
28 
29  bool ShouldBeLooped()
30  {
31  return IsInfiniteLoop || NumberOfLoops > 0;
32  }
33 
34  void CopyDataToBuffer(char* &outBuffer, int nbFrameToCopy, int nbOfChannels)
35  {
36  char* inPtr = AudioDataBuffer + sizeof(short) * nbOfChannels * CurrentFrame;
37  int sizeToCopy = sizeof(short) * nbFrameToCopy * nbOfChannels;
38 
39  memcpy(outBuffer, inPtr, sizeToCopy);
40 
41  CurrentFrame += nbFrameToCopy;
42  outBuffer += sizeToCopy;
43  }
44 
45  int AudioDataMixerCallback(uint busIndex, int totalNbOfFrameToWrite, AudioBufferList* data)
46  {
47  char* outPtr = (char*)data->mBuffers[0].mData;
48 
49  int remainingFramesToWrite = totalNbOfFrameToWrite;
50  while (remainingFramesToWrite > 0)
51  {
52  int nbOfFrameToWrite = std::min(remainingFramesToWrite, (ShouldBeLooped() ? LoopEndPoint : TotalNumberOfFrames) - CurrentFrame);
53 
54  CopyDataToBuffer(outPtr, nbOfFrameToWrite, NumberOfChannels);
55 
56  remainingFramesToWrite -= nbOfFrameToWrite;
57 
58  // Check if the track have to be re-looped
59  if (ShouldBeLooped() && CurrentFrame >= LoopEndPoint)
60  {
61  --NumberOfLoops;
62  CurrentFrame = LoopStartPoint;
63  }
64 
65  // Check if we reached the end of the track.
66  if (CurrentFrame >= TotalNumberOfFrames)
67  {
68  AudioUnitSetParameter((AudioUnit)HandleChannelMixer, kMultiChannelMixerParam_Enable, kAudioUnitScope_Input, busIndex, 0, 0);
69  AudioUnitSetParameter((AudioUnit)Handle3DMixer, k3DMixerParam_Enable, kAudioUnitScope_Input, busIndex, 0, 0);
70 
71  IsEnabled2D = false;
72  IsEnabled3D = false;
73 
74  PlaybackEnded = true;
75 
76  // Fill the rest of the buffer with blank
77  int sizeToBlank = sizeof(short) * NumberOfChannels * remainingFramesToWrite;
78  memset(outPtr, 0, sizeToBlank);
79 
80  return 0;
81  }
82  }
83 
84  return 0;
85  }
86 
87  OSStatus RendererCallbackChannelMixer(uint busNumber, uint numberFrames, AudioBufferList* data)
88  {
89  if (!IsEnabled2D)
90  return 0;
91 
92  OSStatus ret = AudioDataMixerCallback(busNumber, (int)numberFrames, data);
93 
94  return ret;
95  }
96 
97  OSStatus RendererCallback3DMixer(uint busNumber, uint numberFrames, AudioBufferList* data)
98  {
99  if (!IsEnabled3D)
100  return 0;
101 
102  return AudioDataMixerCallback(busNumber, (int)numberFrames, data);
103  }
104 };
105 
106 static OSStatus NullRenderCallback (void *inRefCon,
107  AudioUnitRenderActionFlags *ioActionFlags,
108  const AudioTimeStamp *inTimeStamp,
109  UInt32 inBusNumber,
110  UInt32 inNumberFrames,
111  AudioBufferList *ioData)
112 {
113  memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize);
114 
115  return 0;
116 }
117 
118 static OSStatus DefaultRenderCallbackChannelMixer ( void *inRefCon,
119  AudioUnitRenderActionFlags *ioActionFlags,
120  const AudioTimeStamp *inTimeStamp,
121  UInt32 inBusNumber,
122  UInt32 inNumberFrames,
123  AudioBufferList *ioData)
124 {
125  return ((AudioDataRenderer*)inRefCon)->RendererCallbackChannelMixer(inBusNumber, inNumberFrames, ioData);
126 }
127 
128 static OSStatus DefaultRenderCallback3DMixer ( void *inRefCon,
129  AudioUnitRenderActionFlags *ioActionFlags,
130  const AudioTimeStamp *inTimeStamp,
131  UInt32 inBusNumber,
132  UInt32 inNumberFrames,
133  AudioBufferList *ioData)
134 {
135  return ((AudioDataRenderer*)inRefCon)->RendererCallback3DMixer(inBusNumber, inNumberFrames, ioData);
136 }
137 
138 static AURenderCallbackStruct NullRenderCallbackStruct = { NullRenderCallback, NULL };
139 
140 static std::map<uint, AURenderCallbackStruct*> BusIndexToChannelMixerCallbackStructures;
141 static std::map<uint, AURenderCallbackStruct*> BusIndexTo3DMixerCallbackStructures;
142 
143 extern "C" int SetInputRenderCallbackToChannelMixerDefault(void* inUnit, uint element, void* userData)
144 {
145  AURenderCallbackStruct* pCallbackData = new AURenderCallbackStruct;
146  pCallbackData->inputProc = DefaultRenderCallbackChannelMixer;
147  pCallbackData->inputProcRefCon = userData;
148 
149  int status = AudioUnitSetProperty((AudioUnit)inUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, element, pCallbackData, sizeof(AURenderCallbackStruct));
150 
151  // update BusIndexToChannelMixerCallbackStructures map with last valid data
152  if(BusIndexToChannelMixerCallbackStructures.find(element) != BusIndexToChannelMixerCallbackStructures.end())
153  {
154  if(BusIndexToChannelMixerCallbackStructures[element] != NULL)
155  {
156  delete BusIndexToChannelMixerCallbackStructures[element];
157  BusIndexToChannelMixerCallbackStructures[element] = NULL;
158  }
159  }
160  BusIndexToChannelMixerCallbackStructures[element] = pCallbackData;
161 
162  return status;
163 }
164 
165 extern "C" int SetInputRenderCallbackTo3DMixerDefault(void* inUnit, uint element, void* userData)
166 {
167  AURenderCallbackStruct* pCallbackData = new AURenderCallbackStruct;
168  pCallbackData->inputProc = DefaultRenderCallback3DMixer;
169  pCallbackData->inputProcRefCon = userData;
170 
171  int status = AudioUnitSetProperty((AudioUnit)inUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, element, pCallbackData, sizeof(AURenderCallbackStruct));
172 
173  // update BusIndexTo3DMixerCallbackStructures map with last valid data
174  if(BusIndexTo3DMixerCallbackStructures.find(element) != BusIndexTo3DMixerCallbackStructures.end())
175  {
176  if(BusIndexTo3DMixerCallbackStructures[element] != NULL)
177  {
178  delete BusIndexTo3DMixerCallbackStructures[element];
179  BusIndexTo3DMixerCallbackStructures[element] = NULL;
180  }
181  }
182  BusIndexTo3DMixerCallbackStructures[element] = pCallbackData;
183 
184  return status;
185 }
186 
187 extern "C" int SetInputRenderCallbackToNull(void* inUnit, uint element)
188 {
189  return AudioUnitSetProperty((AudioUnit)inUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, element, &NullRenderCallbackStruct, sizeof(AURenderCallbackStruct));
190 }
191 
192 #endif