ios_audio.m 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #ifdef IRON_A2
  2. #import <AudioToolbox/AudioToolbox.h>
  3. #import <Foundation/Foundation.h>
  4. #include <iron_audio.h>
  5. #include BACKEND_VIDEO_H
  6. #include <iron_math.h>
  7. #include <stdio.h>
  8. #define kOutputBus 0
  9. static iron_internal_video_sound_stream_t *video = NULL;
  10. void iosPlayVideoSoundStream(iron_internal_video_sound_stream_t *v) {
  11. video = v;
  12. }
  13. void iosStopVideoSoundStream(void) {
  14. video = NULL;
  15. }
  16. static void affirm(OSStatus err) {
  17. if (err) {
  18. fprintf(stderr, "Error: %i\n", (int)err);
  19. }
  20. }
  21. static bool initialized;
  22. static bool soundPlaying;
  23. static AudioStreamBasicDescription deviceFormat;
  24. static AudioComponentInstance audioUnit;
  25. static bool isFloat = false;
  26. static bool isInterleaved = true;
  27. static iron_a2_buffer_t a2_buffer;
  28. static void copySample(void *buffer, void *secondary_buffer) {
  29. float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
  30. float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
  31. a2_buffer.read_location += 1;
  32. if (a2_buffer.read_location >= a2_buffer.data_size) {
  33. a2_buffer.read_location = 0;
  34. }
  35. if (video != NULL) {
  36. float *frame = iron_internal_video_sound_stream_next_frame(video);
  37. left_value += frame[0];
  38. left_value = iron_max(iron_min(left_value, 1.0f), -1.0f);
  39. right_value += frame[1];
  40. right_value = iron_max(iron_min(right_value, 1.0f), -1.0f);
  41. if (iron_internal_video_sound_stream_ended(video)) {
  42. video = NULL;
  43. }
  44. }
  45. if (secondary_buffer == NULL) {
  46. if (isFloat) {
  47. ((float *)buffer)[0] = left_value;
  48. ((float *)buffer)[1] = right_value;
  49. }
  50. else {
  51. ((int16_t *)buffer)[0] = (int16_t)(left_value * 32767);
  52. ((int16_t *)buffer)[1] = (int16_t)(right_value * 32767);
  53. }
  54. }
  55. else {
  56. if (isFloat) {
  57. *(float *)buffer = left_value;
  58. *(float *)secondary_buffer = right_value;
  59. }
  60. else {
  61. *(int16_t *)buffer = (int16_t)(left_value * 32767);
  62. *(int16_t *)secondary_buffer = (int16_t)(right_value * 32767);
  63. }
  64. }
  65. }
  66. static OSStatus renderInput(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
  67. UInt32 inNumberFrames, AudioBufferList *outOutputData) {
  68. iron_a2_internal_callback(&a2_buffer, inNumberFrames);
  69. if (isInterleaved) {
  70. if (isFloat) {
  71. float *output = (float *)outOutputData->mBuffers[0].mData;
  72. for (int i = 0; i < inNumberFrames; ++i) {
  73. copySample(output, NULL);
  74. output += 2;
  75. }
  76. }
  77. else {
  78. int16_t *output = (int16_t *)outOutputData->mBuffers[0].mData;
  79. for (int i = 0; i < inNumberFrames; ++i) {
  80. copySample(output, NULL);
  81. output += 2;
  82. }
  83. }
  84. }
  85. else {
  86. if (isFloat) {
  87. float *out1 = (float *)outOutputData->mBuffers[0].mData;
  88. float *out2 = (float *)outOutputData->mBuffers[1].mData;
  89. for (int i = 0; i < inNumberFrames; ++i) {
  90. copySample(out1++, out2++);
  91. }
  92. }
  93. else {
  94. int16_t *out1 = (int16_t *)outOutputData->mBuffers[0].mData;
  95. int16_t *out2 = (int16_t *)outOutputData->mBuffers[1].mData;
  96. for (int i = 0; i < inNumberFrames; ++i) {
  97. copySample(out1++, out2++);
  98. }
  99. }
  100. }
  101. return noErr;
  102. }
  103. static uint32_t samples_per_second = 44100;
  104. static void sampleRateListener(void *inRefCon, AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement) {
  105. Float64 sampleRate;
  106. UInt32 size = sizeof(sampleRate);
  107. affirm(AudioUnitGetProperty(inUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, &size));
  108. if (samples_per_second != (uint32_t)sampleRate) {
  109. samples_per_second = (uint32_t)sampleRate;
  110. iron_a2_internal_sample_rate_callback();
  111. }
  112. }
  113. static bool initialized = false;
  114. void iron_a2_init(void) {
  115. if (initialized) {
  116. return;
  117. }
  118. iron_a2_internal_init();
  119. initialized = true;
  120. a2_buffer.read_location = 0;
  121. a2_buffer.write_location = 0;
  122. a2_buffer.data_size = 128 * 1024;
  123. a2_buffer.channel_count = 2;
  124. a2_buffer.channels[0] = (float *)malloc(a2_buffer.data_size * sizeof(float));
  125. a2_buffer.channels[1] = (float *)malloc(a2_buffer.data_size * sizeof(float));
  126. initialized = false;
  127. AudioComponentDescription desc;
  128. desc.componentType = kAudioUnitType_Output;
  129. desc.componentSubType = kAudioUnitSubType_RemoteIO;
  130. desc.componentFlags = 0;
  131. desc.componentFlagsMask = 0;
  132. desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  133. AudioComponent comp = AudioComponentFindNext(NULL, &desc);
  134. // Get audio units
  135. affirm(AudioComponentInstanceNew(comp, &audioUnit));
  136. UInt32 flag = 1;
  137. affirm(AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(UInt32)));
  138. if (soundPlaying)
  139. return;
  140. affirm(AudioOutputUnitStart(audioUnit));
  141. UInt32 size = sizeof(AudioStreamBasicDescription);
  142. affirm(AudioUnitGetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &deviceFormat, &size));
  143. if (deviceFormat.mFormatID != kAudioFormatLinearPCM) {
  144. fprintf(stderr, "mFormatID != kAudioFormatLinearPCM\n");
  145. return;
  146. }
  147. if (deviceFormat.mFormatFlags & kLinearPCMFormatFlagIsFloat) {
  148. isFloat = true;
  149. }
  150. if (deviceFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) {
  151. isInterleaved = false;
  152. }
  153. AudioUnitAddPropertyListener(audioUnit, kAudioUnitProperty_StreamFormat, sampleRateListener, nil);
  154. initialized = true;
  155. printf("mSampleRate = %g\n", deviceFormat.mSampleRate);
  156. printf("mFormatFlags = %08X\n", (unsigned int)deviceFormat.mFormatFlags);
  157. printf("mBytesPerPacket = %d\n", (unsigned int)deviceFormat.mBytesPerPacket);
  158. printf("mFramesPerPacket = %d\n", (unsigned int)deviceFormat.mFramesPerPacket);
  159. printf("mChannelsPerFrame = %d\n", (unsigned int)deviceFormat.mChannelsPerFrame);
  160. printf("mBytesPerFrame = %d\n", (unsigned int)deviceFormat.mBytesPerFrame);
  161. printf("mBitsPerChannel = %d\n", (unsigned int)deviceFormat.mBitsPerChannel);
  162. if (samples_per_second != (uint32_t)deviceFormat.mSampleRate) {
  163. samples_per_second = (uint32_t)deviceFormat.mSampleRate;
  164. iron_a2_internal_sample_rate_callback();
  165. }
  166. AURenderCallbackStruct callbackStruct;
  167. callbackStruct.inputProc = renderInput;
  168. callbackStruct.inputProcRefCon = NULL;
  169. affirm(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &callbackStruct, sizeof(callbackStruct)));
  170. soundPlaying = true;
  171. }
  172. void iron_a2_update(void) {}
  173. void iron_a2_shutdown(void) {
  174. if (!initialized)
  175. return;
  176. if (!soundPlaying)
  177. return;
  178. affirm(AudioOutputUnitStop(audioUnit));
  179. soundPlaying = false;
  180. }
  181. uint32_t iron_a2_samples_per_second(void) {
  182. return samples_per_second;
  183. }
  184. #endif