diff -Nru faudio-19.08/CMakeLists.txt faudio-19.09/CMakeLists.txt --- faudio-19.08/CMakeLists.txt 2019-08-01 13:56:34.000000000 +0000 +++ faudio-19.09/CMakeLists.txt 2019-09-01 12:55:42.000000000 +0000 @@ -28,7 +28,7 @@ # Version SET(LIB_MAJOR_VERSION "0") SET(LIB_MINOR_VERSION "19") -SET(LIB_REVISION "08") +SET(LIB_REVISION "09") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") # Build Type diff -Nru faudio-19.08/csharp/FAudio.cs faudio-19.09/csharp/FAudio.cs --- faudio-19.08/csharp/FAudio.cs 2019-08-01 13:56:34.000000000 +0000 +++ faudio-19.09/csharp/FAudio.cs 2019-09-01 12:55:42.000000000 +0000 @@ -60,7 +60,7 @@ public const uint FAUDIO_ABI_VERSION = 0; public const uint FAUDIO_MAJOR_VERSION = 19; - public const uint FAUDIO_MINOR_VERSION = 8; + public const uint FAUDIO_MINOR_VERSION = 9; public const uint FAUDIO_PATCH_VERSION = 0; public const uint FAUDIO_COMPILED_VERSION = ( @@ -294,16 +294,16 @@ public const uint FAUDIO_DEFAULT_CHANNELS = 0; public const uint FAUDIO_DEFAULT_SAMPLERATE = 0; - public const byte FAUDIO_DEBUG_ENGINE = 0x01; - public const byte FAUDIO_VOICE_NOPITCH = 0x02; - public const byte FAUDIO_VOICE_NOSRC = 0x04; - public const byte FAUDIO_VOICE_USEFILTER = 0x08; - public const byte FAUDIO_VOICE_MUSIC = 0x10; - public const byte FAUDIO_PLAY_TAILS = 0x20; - public const byte FAUDIO_END_OF_STREAM = 0x40; - public const byte FAUDIO_SEND_USEFILTER = 0x80; - - public const ushort FAUDIO_VOICE_NOSAMPLESPLAYED = 0x0100; + public const uint FAUDIO_DEBUG_ENGINE = 0x0001; + public const uint FAUDIO_VOICE_NOPITCH = 0x0002; + public const uint FAUDIO_VOICE_NOSRC = 0x0004; + public const uint FAUDIO_VOICE_USEFILTER = 0x0008; + public const uint FAUDIO_VOICE_MUSIC = 0x0010; + public const uint FAUDIO_PLAY_TAILS = 0x0020; + public const uint FAUDIO_END_OF_STREAM = 0x0040; + public const uint FAUDIO_SEND_USEFILTER = 0x0080; + public const uint FAUDIO_VOICE_NOSAMPLESPLAYED = 0x0100; + public const uint FAUDIO_1024_QUANTUM = 0x8000; public const FAudioFilterType FAUDIO_DEFAULT_FILTER_TYPE = FAudioFilterType.FAudioLowPassFilter; public const float FAUDIO_DEFAULT_FILTER_FREQUENCY = FAUDIO_MAX_FILTER_FREQUENCY; diff -Nru faudio-19.08/debian/changelog faudio-19.09/debian/changelog --- faudio-19.08/debian/changelog 2019-08-01 22:00:13.000000000 +0000 +++ faudio-19.09/debian/changelog 2019-09-01 15:46:45.000000000 +0000 @@ -1,3 +1,9 @@ +faudio (19.09-bionic~1ppa1) bionic; urgency=medium + + * New upstream release 19.09 + + -- Sveinar Søpler Sun, 01 Sep 2019 17:46:45 +0200 + faudio (19.08-bionic~1ppa1) bionic; urgency=medium * New upstream release 19.08 diff -Nru faudio-19.08/include/FAudio.h faudio-19.09/include/FAudio.h --- faudio-19.08/include/FAudio.h 2019-08-01 13:56:34.000000000 +0000 +++ faudio-19.09/include/FAudio.h 2019-09-01 12:55:42.000000000 +0000 @@ -342,16 +342,16 @@ #define FAUDIO_DEFAULT_CHANNELS 0 #define FAUDIO_DEFAULT_SAMPLERATE 0 -#define FAUDIO_DEBUG_ENGINE 0x01 -#define FAUDIO_VOICE_NOPITCH 0x02 -#define FAUDIO_VOICE_NOSRC 0x04 -#define FAUDIO_VOICE_USEFILTER 0x08 -#define FAUDIO_VOICE_MUSIC 0x10 -#define FAUDIO_PLAY_TAILS 0x20 -#define FAUDIO_END_OF_STREAM 0x40 -#define FAUDIO_SEND_USEFILTER 0x80 - +#define FAUDIO_DEBUG_ENGINE 0x0001 +#define FAUDIO_VOICE_NOPITCH 0x0002 +#define FAUDIO_VOICE_NOSRC 0x0004 +#define FAUDIO_VOICE_USEFILTER 0x0008 +#define FAUDIO_VOICE_MUSIC 0x0010 +#define FAUDIO_PLAY_TAILS 0x0020 +#define FAUDIO_END_OF_STREAM 0x0040 +#define FAUDIO_SEND_USEFILTER 0x0080 #define FAUDIO_VOICE_NOSAMPLESPLAYED 0x0100 +#define FAUDIO_1024_QUANTUM 0x8000 #define FAUDIO_DEFAULT_FILTER_TYPE FAudioLowPassFilter #define FAUDIO_DEFAULT_FILTER_FREQUENCY FAUDIO_MAX_FILTER_FREQUENCY @@ -466,7 +466,7 @@ #define FAUDIO_ABI_VERSION 0 #define FAUDIO_MAJOR_VERSION 19 -#define FAUDIO_MINOR_VERSION 8 +#define FAUDIO_MINOR_VERSION 9 #define FAUDIO_PATCH_VERSION 0 #define FAUDIO_COMPILED_VERSION ( \ diff -Nru faudio-19.08/src/FACT_internal.h faudio-19.09/src/FACT_internal.h --- faudio-19.08/src/FACT_internal.h 2019-08-01 13:56:34.000000000 +0000 +++ faudio-19.09/src/FACT_internal.h 2019-09-01 12:55:42.000000000 +0000 @@ -556,7 +556,7 @@ /* FACT Thread */ -int32_t FACT_INTERNAL_APIThread(void* enginePtr); +int32_t FAUDIOCALL FACT_INTERNAL_APIThread(void* enginePtr); /* FAudio callbacks */ diff -Nru faudio-19.08/src/FAPOBase.c faudio-19.09/src/FAPOBase.c --- faudio-19.08/src/FAPOBase.c 2019-08-01 13:56:34.000000000 +0000 +++ faudio-19.09/src/FAPOBase.c 2019-09-01 12:55:42.000000000 +0000 @@ -361,11 +361,6 @@ /* Add, don't overwrite! */ pOutputBuffer[i * OutputChannelCount + co] += input[i * InputChannelCount + ci]; - pOutputBuffer[i * OutputChannelCount + co] = FAudio_clamp( - pOutputBuffer[i * OutputChannelCount + co], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } else @@ -378,11 +373,6 @@ /* Overwrite, don't add! */ pOutputBuffer[i * OutputChannelCount + co] = input[i * InputChannelCount + ci]; - pOutputBuffer[i * OutputChannelCount + co] = FAudio_clamp( - pOutputBuffer[i * OutputChannelCount + co], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } } diff -Nru faudio-19.08/src/FAudio.c faudio-19.09/src/FAudio.c --- faudio-19.08/src/FAudio.c 2019-08-01 13:56:34.000000000 +0000 +++ faudio-19.09/src/FAudio.c 2019-09-01 12:55:42.000000000 +0000 @@ -200,6 +200,8 @@ FAudio_assert(Flags == 0); FAudio_assert(XAudio2Processor == FAUDIO_DEFAULT_PROCESSOR); + audio->initFlags = Flags; + /* FIXME: This is lazy... */ audio->decodeCache = (float*) audio->pMalloc(sizeof(float)); audio->resampleCache = (float*) audio->pMalloc(sizeof(float)); @@ -617,10 +619,42 @@ FAudio_zero(&(*ppMasteringVoice)->sends, sizeof(FAudioVoiceSends)); FAudioVoice_SetEffectChain(*ppMasteringVoice, pEffectChain); - /* Platform Device */ + /* This is now safe enough to assign */ audio->master = *ppMasteringVoice; + + /* Build the device format. + * The most unintuitive part of this is the use of outputChannels + * instead of master.inputChannels. Bizarrely, the effect chain can + * dictate the _actual_ output channel count, and when the channel count + * mismatches, we have to add a staging buffer for effects to process on + * before ultimately copying the final result to the device. ARGH. + */ + WriteWaveFormatExtensible( + &audio->mixFormat, + audio->master->outputChannels, + audio->master->master.inputSampleRate + ); + + /* Platform Device */ FAudio_AddRef(audio); - FAudio_PlatformInit(audio, DeviceIndex); + FAudio_PlatformInit( + audio, + audio->initFlags, + DeviceIndex, + &audio->mixFormat, + &audio->updateSize, + &audio->platform + ); + if (audio->platform == NULL) + { + FAudioVoice_DestroyVoice(*ppMasteringVoice); + *ppMasteringVoice = NULL; + + /* Not the best code, but it's probably true? */ + return FAUDIO_E_DEVICE_INVALIDATED; + } + audio->master->outputChannels = audio->mixFormat.Format.nChannels; + audio->master->master.inputSampleRate = audio->mixFormat.Format.nSamplesPerSec; /* Effect Chain Cache */ if ((*ppMasteringVoice)->master.inputChannels != (*ppMasteringVoice)->outputChannels) @@ -1612,7 +1646,7 @@ /* Find the send index */ if (pDestinationVoice == NULL && voice->sends.SendCount == 1) { - pDestinationVoice = voice->audio->master; + pDestinationVoice = voice->sends.pSends[0].pOutputVoice; } for (i = 0; i < voice->sends.SendCount; i += 1) { @@ -1680,7 +1714,7 @@ /* Find the send index */ if (pDestinationVoice == NULL && voice->sends.SendCount == 1) { - pDestinationVoice = voice->audio->master; + pDestinationVoice = voice->sends.pSends[0].pOutputVoice; } for (i = 0; i < voice->sends.SendCount; i += 1) { @@ -1859,7 +1893,7 @@ /* Find the send index */ if (pDestinationVoice == NULL && voice->sends.SendCount == 1) { - pDestinationVoice = voice->audio->master; + pDestinationVoice = voice->sends.pSends[0].pOutputVoice; } FAudio_assert(pDestinationVoice != NULL); for (i = 0; i < voice->sends.SendCount; i += 1) @@ -2036,7 +2070,15 @@ } else if (voice->type == FAUDIO_VOICE_MASTER) { - FAudio_PlatformQuit(voice->audio); + if (voice->audio->platform != NULL) + { + FAudio_PlatformQuit(voice->audio->platform); + voice->audio->platform = NULL; + } + if (voice->master.effectCache != NULL) + { + voice->audio->pFree(voice->master.effectCache); + } voice->audio->master = NULL; } diff -Nru faudio-19.08/src/FAudio_internal.h faudio-19.09/src/FAudio_internal.h --- faudio-19.08/src/FAudio_internal.h 2019-08-01 13:56:34.000000000 +0000 +++ faudio-19.09/src/FAudio_internal.h 2019-09-01 12:55:42.000000000 +0000 @@ -343,6 +343,7 @@ uint8_t version; uint8_t active; uint32_t refcount; + uint32_t initFlags; uint32_t updateSize; FAudioMasteringVoice *master; LinkedList *sources; @@ -713,8 +714,15 @@ void FAudio_PlatformAddRef(void); void FAudio_PlatformRelease(void); -void FAudio_PlatformInit(FAudio *audio, uint32_t deviceIndex); -void FAudio_PlatformQuit(FAudio *audio); +void FAudio_PlatformInit( + FAudio *audio, + uint32_t flags, + uint32_t deviceIndex, + FAudioWaveFormatExtensible *mixFormat, + uint32_t *updateSize, + void** platformDevice +); +void FAudio_PlatformQuit(void* platformDevice); uint32_t FAudio_PlatformGetDeviceCount(void); uint32_t FAudio_PlatformGetDeviceDetails( @@ -742,6 +750,45 @@ uint32_t FAudio_timems(void); +/* WaveFormatExtensible Helpers */ + +static inline uint32_t GetMask(uint16_t channels) +{ + if (channels == 1) return SPEAKER_MONO; + if (channels == 2) return SPEAKER_STEREO; + if (channels == 3) return SPEAKER_2POINT1; + if (channels == 4) return SPEAKER_QUAD; + if (channels == 5) return SPEAKER_4POINT1; + if (channels == 6) return SPEAKER_5POINT1; + if (channels == 8) return SPEAKER_7POINT1; + FAudio_assert(0 && "Unrecognized speaker layout!"); + return 0; +} + +static inline void WriteWaveFormatExtensible( + FAudioWaveFormatExtensible *fmt, + int channels, + int samplerate +) { + FAudio_assert(fmt != NULL); + fmt->Format.wBitsPerSample = 32; + fmt->Format.wFormatTag = FAUDIO_FORMAT_EXTENSIBLE; + fmt->Format.nChannels = channels; + fmt->Format.nSamplesPerSec = samplerate; + fmt->Format.nBlockAlign = ( + fmt->Format.nChannels * + (fmt->Format.wBitsPerSample / 8) + ); + fmt->Format.nAvgBytesPerSec = ( + fmt->Format.nSamplesPerSec * + fmt->Format.nBlockAlign + ); + fmt->Format.cbSize = sizeof(FAudioWaveFormatExtensible) - sizeof(FAudioWaveFormatEx); + fmt->Samples.wValidBitsPerSample = 32; + fmt->dwChannelMask = GetMask(fmt->Format.nChannels); + FAudio_memcpy(&fmt->SubFormat, &DATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(FAudioGUID)); +} + /* Resampling */ /* Okay, so here's what all this fixed-point goo is for: diff -Nru faudio-19.08/src/FAudio_internal_simd.c faudio-19.09/src/FAudio_internal_simd.c --- faudio-19.08/src/FAudio_internal_simd.c 2019-08-01 13:56:34.000000000 +0000 +++ faudio-19.09/src/FAudio_internal_simd.c 2019-09-01 12:55:42.000000000 +0000 @@ -33,26 +33,36 @@ */ #if defined(__x86_64__) || defined(_M_X64) -#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* x86_64 guarantees SSE2. */ -#ifndef __SSE2__ /* For some reason this is not always defined? -flibit */ -#define __SSE2__ -#endif -#elif __MACOSX__ -#ifndef __SSE2__ -#error macOS does not have SSE2? Bad compiler? They actually moved to ARM?! -#endif -#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* Mac OS X/Intel guarantees SSE2. */ + /* Some platforms fail to define this... */ + #ifndef __SSE2__ + #define __SSE2__ 1 + #endif + + /* x86_64 guarantees SSE2. */ + #define NEED_SCALAR_CONVERTER_FALLBACKS 0 #elif defined(__aarch64__) || defined(_M_ARM64) -#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* AArch64 guarantees NEON. */ + /* Some platforms fail to define this... */ + #ifndef __ARM_NEON__ + #define __ARM_NEON__ 1 + #endif + + /* AArch64 guarantees NEON. */ + #define NEED_SCALAR_CONVERTER_FALLBACKS 0 +#elif __MACOSX__ + /* Some build systems may need to specify this. Also, macOS ARM? Sigh */ + #ifndef __SSE2__ + #error macOS does not have SSE2? Bad compiler? They actually moved to ARM?! + #endif + + /* Mac OS X/Intel guarantees SSE2. */ + #define NEED_SCALAR_CONVERTER_FALLBACKS 0 #else -#define NEED_SCALAR_CONVERTER_FALLBACKS 1 + /* Need plain C implementations to support all other hardware */ + #define NEED_SCALAR_CONVERTER_FALLBACKS 1 #endif -/* Our NEON paths require AArch64 */ +/* Our NEON paths require AArch64, don't check __ARM_NEON__ here */ #if defined(__aarch64__) || defined(_M_ARM64) -#ifndef __ARM_NEON__ /* Some platforms fail to define this... */ -#define __ARM_NEON__ 1 -#endif #include #define HAVE_NEON_INTRINSICS 1 #endif @@ -275,10 +285,10 @@ const uint16x8_t uint16hi = vmovl_u8(vget_high_u8(bytes)); /* convert top 8 bytes to 8 uint16 */ const uint16x8_t uint16lo = vmovl_u8(vget_low_u8(bytes)); /* convert bottom 8 bytes to 8 uint16 */ /* split uint16 to two uint32, then convert to float, then multiply to normalize, subtract to adjust for sign, store. */ - vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128)); - vst1q_f32(dst+4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128)); - vst1q_f32(dst+8, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128)); - vst1q_f32(dst+12, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128)); + vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128)); + vst1q_f32(dst+4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128)); + vst1q_f32(dst+8, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128)); + vst1q_f32(dst+12, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128)); i -= 16; mmsrc -= 16; dst -= 16; } @@ -1182,11 +1192,6 @@ for (i = 0; i < totalSamples; i += 1) { output[i] *= volume; - output[i] = FAudio_clamp( - output[i], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } #endif /* NEED_SCALAR_CONVERTER_FALLBACKS */ @@ -1202,7 +1207,7 @@ uint32_t i; uint32_t header = (16 - (((size_t) output) % 16)) / 4; uint32_t tail = (totalSamples - header) % 4; - __m128 volumeVec, minVolumeVec, maxVolumeVec, outVec; + __m128 volumeVec, outVec; if (header == 4) { header = 0; @@ -1215,33 +1220,19 @@ for (i = 0; i < header; i += 1) { output[i] *= volume; - output[i] = FAudio_clamp( - output[i], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } volumeVec = _mm_set1_ps(volume); - minVolumeVec = _mm_set1_ps(-FAUDIO_MAX_VOLUME_LEVEL); - maxVolumeVec = _mm_set1_ps(FAUDIO_MAX_VOLUME_LEVEL); for (i = header; i < totalSamples - tail; i += 4) { outVec = _mm_load_ps(output + i); outVec = _mm_mul_ps(outVec, volumeVec); - outVec = _mm_max_ps(outVec, minVolumeVec); - outVec = _mm_min_ps(outVec, maxVolumeVec); _mm_store_ps(output + i, outVec); } for (i = totalSamples - tail; i < totalSamples; i += 1) { output[i] *= volume; - output[i] = FAudio_clamp( - output[i], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } #endif /* HAVE_SSE2_INTRINSICS */ @@ -1255,7 +1246,7 @@ uint32_t i; uint32_t header = (16 - (((size_t) output) % 16)) / 4; uint32_t tail = (totalSamples - header) % 4; - float32x4_t volumeVec, minVolumeVec, maxVolumeVec, outVec; + float32x4_t volumeVec, outVec; if (header == 4) { header = 0; @@ -1268,33 +1259,19 @@ for (i = 0; i < header; i += 1) { output[i] *= volume; - output[i] = FAudio_clamp( - output[i], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } volumeVec = vdupq_n_f32(volume); - minVolumeVec = vdupq_n_f32(-FAUDIO_MAX_VOLUME_LEVEL); - maxVolumeVec = vdupq_n_f32(FAUDIO_MAX_VOLUME_LEVEL); for (i = header; i < totalSamples - tail; i += 4) { outVec = vld1q_f32(output + i); outVec = vmulq_f32(outVec, volumeVec); - outVec = vmaxq_f32(outVec, minVolumeVec); - outVec = vminq_f32(outVec, maxVolumeVec); vst1q_f32(output + i, outVec); } for (i = totalSamples - tail; i < totalSamples; i += 1) { output[i] *= volume; - output[i] = FAudio_clamp( - output[i], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } #endif /* HAVE_NEON_INTRINSICS */ @@ -1324,11 +1301,6 @@ coefficients[co * srcChans + ci] ); } - dst[co] = FAudio_clamp( - dst[co], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } @@ -1346,15 +1318,8 @@ float totalVolume = baseVolume * channelVolume[0] * coefficients[0]; for (i = 0; i < toMix; i += 1, src += 1, dst += 1) { - /* Base source data, combined with the coefficients... */ + /* Base source data, combined with the coefficients */ dst[0] += src[0] * totalVolume; - - /* ... then clamped. */ - dst[0] = FAudio_clamp( - dst[0], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } @@ -1375,21 +1340,9 @@ /* Base source data... */ const float sample = src[0] * totalVolume; - /* ... combined with the coefficients... */ + /* ... combined with the coefficients. */ dst[0] += sample * coefficients[0]; dst[1] += sample * coefficients[1]; - - /* ... then clamped. */ - dst[0] = FAudio_clamp( - dst[0], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[1] = FAudio_clamp( - dst[1], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } @@ -1410,45 +1363,13 @@ /* Base source data... */ const float sample = src[0] * totalVolume; - /* ... combined with the coefficients... */ + /* ... combined with the coefficients. */ dst[0] += sample * coefficients[0]; dst[1] += sample * coefficients[1]; dst[2] += sample * coefficients[2]; dst[3] += sample * coefficients[3]; dst[4] += sample * coefficients[4]; dst[5] += sample * coefficients[5]; - - /* ... then clamped. */ - dst[0] = FAudio_clamp( - dst[0], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[1] = FAudio_clamp( - dst[1], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[2] = FAudio_clamp( - dst[2], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[3] = FAudio_clamp( - dst[3], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[4] = FAudio_clamp( - dst[4], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[5] = FAudio_clamp( - dst[5], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } @@ -1469,7 +1390,7 @@ /* Base source data... */ const float sample = src[0] * totalVolume; - /* ... combined with the coefficients... */ + /* ... combined with the coefficients. */ dst[0] += sample * coefficients[0]; dst[1] += sample * coefficients[1]; dst[2] += sample * coefficients[2]; @@ -1478,48 +1399,6 @@ dst[5] += sample * coefficients[5]; dst[6] += sample * coefficients[6]; dst[7] += sample * coefficients[7]; - - /* ... then clamped. */ - dst[0] = FAudio_clamp( - dst[0], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[1] = FAudio_clamp( - dst[1], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[2] = FAudio_clamp( - dst[2], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[3] = FAudio_clamp( - dst[3], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[4] = FAudio_clamp( - dst[4], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[5] = FAudio_clamp( - dst[5], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[6] = FAudio_clamp( - dst[6], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[7] = FAudio_clamp( - dst[7], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } @@ -1538,18 +1417,11 @@ float totalVolumeR = baseVolume * channelVolume[1] * coefficients[1]; for (i = 0; i < toMix; i += 1, src += 2, dst += 1) { - /* Base source data, combined with the coefficients... */ + /* Base source data, combined with the coefficients */ dst[0] += ( (src[0] * totalVolumeL) + (src[1] * totalVolumeR) ); - - /* ... then clamped. */ - dst[0] = FAudio_clamp( - dst[0], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } @@ -1572,7 +1444,7 @@ const float left = src[0] * totalVolumeL; const float right = src[1] * totalVolumeR; - /* ... combined with the coefficients... */ + /* ... combined with the coefficients. */ dst[0] += ( (left * coefficients[0]) + (right * coefficients[1]) @@ -1581,18 +1453,6 @@ (left * coefficients[2]) + (right * coefficients[3]) ); - - /* ... then clamped. */ - dst[0] = FAudio_clamp( - dst[0], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[1] = FAudio_clamp( - dst[1], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } @@ -1615,7 +1475,7 @@ const float left = src[0] * totalVolumeL; const float right = src[1] * totalVolumeR; - /* ... combined with the coefficients... */ + /* ... combined with the coefficients. */ dst[0] += ( (left * coefficients[0]) + (right * coefficients[1]) @@ -1640,38 +1500,6 @@ (left * coefficients[10]) + (right * coefficients[11]) ); - - /* ... then clamped. */ - dst[0] = FAudio_clamp( - dst[0], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[1] = FAudio_clamp( - dst[1], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[2] = FAudio_clamp( - dst[2], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[3] = FAudio_clamp( - dst[3], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[4] = FAudio_clamp( - dst[4], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[5] = FAudio_clamp( - dst[5], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } @@ -1694,7 +1522,7 @@ const float left = src[0] * totalVolumeL; const float right = src[1] * totalVolumeR; - /* ... combined with the coefficients... */ + /* ... combined with the coefficients. */ dst[0] += ( (left * coefficients[0]) + (right * coefficients[1]) @@ -1727,48 +1555,6 @@ (left * coefficients[14]) + (right * coefficients[15]) ); - - /* ... then clamped. */ - dst[0] = FAudio_clamp( - dst[0], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[1] = FAudio_clamp( - dst[1], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[2] = FAudio_clamp( - dst[2], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[3] = FAudio_clamp( - dst[3], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[4] = FAudio_clamp( - dst[4], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[5] = FAudio_clamp( - dst[5], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[6] = FAudio_clamp( - dst[6], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); - dst[7] = FAudio_clamp( - dst[7], - -FAUDIO_MAX_VOLUME_LEVEL, - FAUDIO_MAX_VOLUME_LEVEL - ); } } diff -Nru faudio-19.08/src/FAudio_platform_sdl2.c faudio-19.09/src/FAudio_platform_sdl2.c --- faudio-19.08/src/FAudio_platform_sdl2.c 2019-08-01 13:56:34.000000000 +0000 +++ faudio-19.09/src/FAudio_platform_sdl2.c 2019-09-01 12:55:42.000000000 +0000 @@ -28,47 +28,9 @@ #include -/* WaveFormatExtensible Helpers */ - -static inline uint32_t GetMask(uint16_t channels) -{ - if (channels == 1) return SPEAKER_MONO; - if (channels == 2) return SPEAKER_STEREO; - if (channels == 3) return SPEAKER_2POINT1; - if (channels == 4) return SPEAKER_QUAD; - if (channels == 5) return SPEAKER_4POINT1; - if (channels == 6) return SPEAKER_5POINT1; - if (channels == 8) return SPEAKER_7POINT1; - FAudio_assert(0 && "Unrecognized speaker layout!"); - return 0; -} - -static inline void WriteWaveFormatExtensible( - FAudioWaveFormatExtensible *fmt, - int channels, - int samplerate -) { - fmt->Format.wBitsPerSample = 32; - fmt->Format.wFormatTag = FAUDIO_FORMAT_EXTENSIBLE; - fmt->Format.nChannels = channels; - fmt->Format.nSamplesPerSec = samplerate; - fmt->Format.nBlockAlign = ( - fmt->Format.nChannels * - (fmt->Format.wBitsPerSample / 8) - ); - fmt->Format.nAvgBytesPerSec = ( - fmt->Format.nSamplesPerSec * - fmt->Format.nBlockAlign - ); - fmt->Format.cbSize = sizeof(FAudioWaveFormatExtensible) - sizeof(FAudioWaveFormatEx); - fmt->Samples.wValidBitsPerSample = 32; - fmt->dwChannelMask = GetMask(fmt->Format.nChannels); - FAudio_memcpy(&fmt->SubFormat, &DATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(FAudioGUID)); -} - /* Mixer Thread */ -void FAudio_INTERNAL_MixCallback(void *userdata, Uint8 *stream, int len) +static void FAudio_INTERNAL_MixCallback(void *userdata, Uint8 *stream, int len) { FAudio *audio = (FAudio*) userdata; @@ -103,34 +65,38 @@ SDL_QuitSubSystem(SDL_INIT_AUDIO); } -void FAudio_PlatformInit(FAudio *audio, uint32_t deviceIndex) -{ +void FAudio_PlatformInit( + FAudio *audio, + uint32_t flags, + uint32_t deviceIndex, + FAudioWaveFormatExtensible *mixFormat, + uint32_t *updateSize, + void** platformDevice +) { SDL_AudioDeviceID device; SDL_AudioSpec want, have; - /* Build the device format. - * The most unintuitive part of this is the use of outputChannels - * instead of master.inputChannels. Bizarrely, the effect chain can - * dictate the _actual_ output channel count, and when the channel count - * mismatches, we have to add a staging buffer for effects to process on - * before ultimately copying the final result to the device. ARGH. - */ - want.freq = audio->master->master.inputSampleRate; + FAudio_assert(mixFormat != NULL); + FAudio_assert(updateSize != NULL); + + /* Build the device spec */ + want.freq = mixFormat->Format.nSamplesPerSec; want.format = AUDIO_F32; - want.channels = audio->master->outputChannels; + want.channels = mixFormat->Format.nChannels; want.silence = 0; want.samples = 1024; want.callback = FAudio_INTERNAL_MixCallback; want.userdata = audio; - /* Open the device, finally. */ + /* Open the device (or at least try to) */ +iosretry: device = SDL_OpenAudioDevice( deviceIndex > 0 ? SDL_GetAudioDeviceName(deviceIndex - 1, 0) : NULL, 0, &want, &have, #if SDL_VERSION_ATLEAST(2, 0, 9) - SDL_AUDIO_ALLOW_SAMPLES_CHANGE + (flags & FAUDIO_1024_QUANTUM) ? 0 : SDL_AUDIO_ALLOW_SAMPLES_CHANGE #else #ifdef _WIN32 #error Windows absolutely positively needs SDL 2.0.9! @@ -142,30 +108,43 @@ ); if (device == 0) { - SDL_Log("OpenAudioDevice failed: %s\n", SDL_GetError()); + const char *err = SDL_GetError(); + SDL_Log("OpenAudioDevice failed: %s\n", err); + + /* iOS has a weird thing where you can't open a stream when the + * app is in the background, even though the program is meant + * to be suspended and thus not trip this in the first place. + * + * Startup suspend behavior when an app is opened then closed + * is a big pile of crap, basically. + * + * Google the error code and you'll find that this has been a + * long-standing issue that nobody seems to care about. + * -flibit + */ + if (SDL_strstr(err, "Code=561015905") != NULL) + { + goto iosretry; + } + FAudio_assert(0 && "Failed to open audio device!"); return; } - /* Write up the format for the engine */ - WriteWaveFormatExtensible(&audio->mixFormat, have.channels, have.freq); - audio->updateSize = have.samples; - - /* Also give some info to the master voice */ - audio->master->outputChannels = have.channels; - audio->master->master.inputSampleRate = have.freq; + /* Write up the received format for the engine */ + WriteWaveFormatExtensible(mixFormat, have.channels, have.freq); + *updateSize = have.samples; + + /* SDL_AudioDeviceID is a Uint32, anybody using a 16-bit PC still? */ + *platformDevice = (void*) ((size_t) device); /* Start the thread! */ SDL_PauseAudioDevice(device, 0); - - /* SDL_AudioDeviceID is a Uint32, anybody using a 16-bit PC still? */ - audio->platform = (void*) ((size_t) device); } -void FAudio_PlatformQuit(FAudio *audio) +void FAudio_PlatformQuit(void* platformDevice) { - SDL_CloseAudioDevice((SDL_AudioDeviceID) ((size_t) audio->platform)); - audio->platform = NULL; + SDL_CloseAudioDevice((SDL_AudioDeviceID) ((size_t) platformDevice)); } uint32_t FAudio_PlatformGetDeviceCount() @@ -198,6 +177,19 @@ { name = "Default Device"; details->Role = FAudioGlobalDefaultDevice; + + /* This variable will look like a DSound GUID or WASAPI ID, i.e. + * "{0.0.0.00000000}.{FD47D9CC-4218-4135-9CE2-0C195C87405B}" + */ + envvar = SDL_getenv("FAUDIO_FORCE_DEFAULT_DEVICEID"); + if (envvar != NULL) + { + FAudio_UTF8_To_UTF16( + envvar, + (uint16_t*) details->DeviceID, + sizeof(details->DeviceID) + ); + } } else {