diff options
Diffstat (limited to 'src/audio_core')
-rw-r--r-- | src/audio_core/codec.cpp | 2 | ||||
-rw-r--r-- | src/audio_core/hle/dsp.cpp | 3 | ||||
-rw-r--r-- | src/audio_core/hle/dsp.h | 72 | ||||
-rw-r--r-- | src/audio_core/hle/filter.cpp | 2 | ||||
-rw-r--r-- | src/audio_core/hle/mixers.cpp | 5 | ||||
-rw-r--r-- | src/audio_core/hle/pipe.cpp | 10 | ||||
-rw-r--r-- | src/audio_core/hle/pipe.h | 14 | ||||
-rw-r--r-- | src/audio_core/hle/source.cpp | 44 | ||||
-rw-r--r-- | src/audio_core/interpolate.cpp | 20 | ||||
-rw-r--r-- | src/audio_core/interpolate.h | 4 | ||||
-rw-r--r-- | src/audio_core/null_sink.h | 3 | ||||
-rw-r--r-- | src/audio_core/sink.h | 4 | ||||
-rw-r--r-- | src/audio_core/sink_details.h | 3 |
13 files changed, 110 insertions, 76 deletions
diff --git a/src/audio_core/codec.cpp b/src/audio_core/codec.cpp index c7efae753..4edfe9be0 100644 --- a/src/audio_core/codec.cpp +++ b/src/audio_core/codec.cpp @@ -23,7 +23,7 @@ StereoBuffer16 DecodeADPCM(const u8* const data, const size_t sample_count, constexpr size_t FRAME_LEN = 8; constexpr size_t SAMPLES_PER_FRAME = 14; - constexpr std::array<int, 16> SIGNED_NIBBLES{ + constexpr std::array<int, 16> SIGNED_NIBBLES = { {0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}}; const size_t ret_size = diff --git a/src/audio_core/hle/dsp.cpp b/src/audio_core/hle/dsp.cpp index 5c8afa111..aaa3a280f 100644 --- a/src/audio_core/hle/dsp.cpp +++ b/src/audio_core/hle/dsp.cpp @@ -49,7 +49,8 @@ static SharedMemory& WriteRegion() { static std::array<Source, num_sources> sources = { Source(0), Source(1), Source(2), Source(3), Source(4), Source(5), Source(6), Source(7), Source(8), Source(9), Source(10), Source(11), Source(12), Source(13), Source(14), Source(15), - Source(16), Source(17), Source(18), Source(19), Source(20), Source(21), Source(22), Source(23)}; + Source(16), Source(17), Source(18), Source(19), Source(20), Source(21), Source(22), Source(23), +}; static Mixers mixers; static StereoFrame16 GenerateCurrentFrame() { diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h index 5b216eb87..f4c4b01e2 100644 --- a/src/audio_core/hle/dsp.h +++ b/src/audio_core/hle/dsp.h @@ -23,16 +23,15 @@ class Sink; namespace DSP { namespace HLE { -// The application-accessible region of DSP memory consists of two parts. -// Both are marked as IO and have Read/Write permissions. +// The application-accessible region of DSP memory consists of two parts. Both are marked as IO and +// have Read/Write permissions. // // First Region: 0x1FF50000 (Size: 0x8000) // Second Region: 0x1FF70000 (Size: 0x8000) // // The DSP reads from each region alternately based on the frame counter for each region much like a // double-buffer. The frame counter is located as the very last u16 of each region and is -// incremented -// each audio tick. +// incremented each audio tick. constexpr VAddr region0_base = 0x1FF50000; constexpr VAddr region1_base = 0x1FF70000; @@ -92,14 +91,12 @@ static_assert(std::is_trivially_copyable<u32_dsp>::value, "u32_dsp isn't trivial // See also: DSP::HLE::PipeRead. // // Note that the above addresses do vary slightly between audio firmwares observed; the addresses -// are -// not fixed in stone. The addresses above are only an examplar; they're what this implementation -// does and provides to applications. +// are not fixed in stone. The addresses above are only an examplar; they're what this +// implementation does and provides to applications. // // Application requests the DSP service to convert DSP addresses into ARM11 virtual addresses using -// the -// ConvertProcessAddressFromDspDram service call. Applications seem to derive the addresses for the -// second region via: +// the ConvertProcessAddressFromDspDram service call. Applications seem to derive the addresses for +// the second region via: // second_region_dsp_addr = first_region_dsp_addr | 0x10000 // // Applications maintain most of its own audio state, the memory region is used mainly for @@ -107,7 +104,7 @@ static_assert(std::is_trivially_copyable<u32_dsp>::value, "u32_dsp isn't trivial // // In the documentation below, filter and effect transfer functions are specified in the z domain. // (If you are more familiar with the Laplace transform, z = exp(sT). The z domain is the digital -// frequency domain, just like how the s domain is the analog frequency domain.) +// frequency domain, just like how the s domain is the analog frequency domain.) #define INSERT_PADDING_DSPWORDS(num_words) INSERT_PADDING_BYTES(2 * (num_words)) @@ -137,8 +134,8 @@ struct SourceConfiguration { BitField<0, 1, u32_le> format_dirty; BitField<1, 1, u32_le> mono_or_stereo_dirty; BitField<2, 1, u32_le> adpcm_coefficients_dirty; - BitField<3, 1, u32_le> - partial_embedded_buffer_dirty; ///< Tends to be set when a looped buffer is queued. + /// Tends to be set when a looped buffer is queued. + BitField<3, 1, u32_le> partial_embedded_buffer_dirty; BitField<4, 1, u32_le> partial_reset_flag; BitField<16, 1, u32_le> enable_dirty; @@ -146,8 +143,8 @@ struct SourceConfiguration { BitField<18, 1, u32_le> rate_multiplier_dirty; BitField<19, 1, u32_le> buffer_queue_dirty; BitField<20, 1, u32_le> loop_related_dirty; - BitField<21, 1, u32_le> - play_position_dirty; ///< Tends to also be set when embedded buffer is updated. + /// Tends to also be set when embedded buffer is updated. + BitField<21, 1, u32_le> play_position_dirty; BitField<22, 1, u32_le> filters_enabled_dirty; BitField<23, 1, u32_le> simple_filter_dirty; BitField<24, 1, u32_le> biquad_filter_dirty; @@ -162,9 +159,9 @@ struct SourceConfiguration { // Gain control /** - * Gain is between 0.0-1.0. This determines how much will this source appear on - * each of the 12 channels that feed into the intermediate mixers. - * Each of the three intermediate mixers is fed two left and two right channels. + * Gain is between 0.0-1.0. This determines how much will this source appear on each of the + * 12 channels that feed into the intermediate mixers. Each of the three intermediate mixers + * is fed two left and two right channels. */ float_le gain[3][4]; @@ -173,7 +170,11 @@ struct SourceConfiguration { /// Multiplier for sample rate. Resampling occurs with the selected interpolation method. float_le rate_multiplier; - enum class InterpolationMode : u8 { Polyphase = 0, Linear = 1, None = 2 }; + enum class InterpolationMode : u8 { + Polyphase = 0, + Linear = 1, + None = 2, + }; InterpolationMode interpolation_mode; INSERT_PADDING_BYTES(1); ///< Interpolation related @@ -197,8 +198,7 @@ struct SourceConfiguration { * The transfer function of this filter is: * H(z) = (b0 + b1 z^-1 + b2 z^-2) / (1 - a1 z^-1 - a2 z^-2) * Nintendo chose to negate the feedbackward coefficients. This differs from standard - * notation - * as in: https://ccrma.stanford.edu/~jos/filters/Direct_Form_I.html + * notation as in: https://ccrma.stanford.edu/~jos/filters/Direct_Form_I.html * Values are signed fixed point with 14 fractional bits. */ struct BiquadFilter { @@ -246,8 +246,8 @@ struct SourceConfiguration { u8 is_looping; /// This value is shown in SourceStatus::previous_buffer_id when this buffer has - /// finished. - /// This allows the emulated application to tell what buffer is currently playing + /// finished. This allows the emulated application to tell what buffer is currently + /// playing. u16_le buffer_id; INSERT_PADDING_DSPWORDS(1); @@ -275,9 +275,16 @@ struct SourceConfiguration { /// Note a sample takes up different number of bytes in different buffer formats. u32_dsp length; - enum class MonoOrStereo : u16_le { Mono = 1, Stereo = 2 }; + enum class MonoOrStereo : u16_le { + Mono = 1, + Stereo = 2, + }; - enum class Format : u16_le { PCM8 = 0, PCM16 = 1, ADPCM = 2 }; + enum class Format : u16_le { + PCM8 = 0, + PCM16 = 1, + ADPCM = 2, + }; union { u16_le flags1_raw; @@ -349,12 +356,16 @@ struct DspConfiguration { }; /// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for - /// each at the final mixer + /// each at the final mixer. float_le volume[3]; INSERT_PADDING_DSPWORDS(3); - enum class OutputFormat : u16_le { Mono = 0, Stereo = 1, Surround = 2 }; + enum class OutputFormat : u16_le { + Mono = 0, + Stereo = 1, + Surround = 2, + }; OutputFormat output_format; @@ -386,9 +397,10 @@ struct DspConfiguration { u16_le enable; INSERT_PADDING_DSPWORDS(1); u16_le outputs; - u32_dsp work_buffer_address; ///< The application allocates a block of memory for the DSP to - /// use as a work buffer. - u16_le frame_count; ///< Frames to delay by + /// The application allocates a block of memory for the DSP to use as a work buffer. + u32_dsp work_buffer_address; + /// Frames to delay by + u16_le frame_count; // Coefficients s16_le g; ///< Fixed point with 7 fractional bits diff --git a/src/audio_core/hle/filter.cpp b/src/audio_core/hle/filter.cpp index ab8814e59..da2a4684e 100644 --- a/src/audio_core/hle/filter.cpp +++ b/src/audio_core/hle/filter.cpp @@ -61,6 +61,7 @@ void SourceFilters::SimpleFilter::Reset() { void SourceFilters::SimpleFilter::Configure( SourceConfiguration::Configuration::SimpleFilter config) { + a1 = config.a1; b0 = config.b0; } @@ -91,6 +92,7 @@ void SourceFilters::BiquadFilter::Reset() { void SourceFilters::BiquadFilter::Configure( SourceConfiguration::Configuration::BiquadFilter config) { + a1 = config.a1; a2 = config.a2; b0 = config.b0; diff --git a/src/audio_core/hle/mixers.cpp b/src/audio_core/hle/mixers.cpp index a661a7b27..126f328bc 100644 --- a/src/audio_core/hle/mixers.cpp +++ b/src/audio_core/hle/mixers.cpp @@ -77,9 +77,8 @@ void Mixers::ParseConfig(DspConfiguration& config) { if (config.headphones_connected_dirty) { config.headphones_connected_dirty.Assign(0); - // Do nothing. - // (Note: Whether headphones are connected does affect coefficients used for surround - // sound.) + // Do nothing. (Note: Whether headphones are connected does affect coefficients used for + // surround sound.) LOG_TRACE(Audio_DSP, "mixers headphones_connected=%hu", config.headphones_connected); } diff --git a/src/audio_core/hle/pipe.cpp b/src/audio_core/hle/pipe.cpp index fe67d2503..f2b6d6552 100644 --- a/src/audio_core/hle/pipe.cpp +++ b/src/audio_core/hle/pipe.cpp @@ -97,7 +97,8 @@ static void AudioPipeWriteStructAddresses() { 0x8000 + offsetof(SharedMemory, unknown11) / 2, 0x8000 + offsetof(SharedMemory, unknown12) / 2, 0x8000 + offsetof(SharedMemory, unknown13) / 2, - 0x8000 + offsetof(SharedMemory, unknown14) / 2}; + 0x8000 + offsetof(SharedMemory, unknown14) / 2, + }; // Begin with a u16 denoting the number of structs. WriteU16(DspPipe::Audio, static_cast<u16>(struct_addresses.size())); @@ -118,7 +119,12 @@ void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) { return; } - enum class StateChange { Initalize = 0, Shutdown = 1, Wakeup = 2, Sleep = 3 }; + enum class StateChange { + Initalize = 0, + Shutdown = 1, + Wakeup = 2, + Sleep = 3, + }; // The difference between Initialize and Wakeup is that Input state is maintained // when sleeping but isn't when turning it off and on again. (TODO: Implement this.) diff --git a/src/audio_core/hle/pipe.h b/src/audio_core/hle/pipe.h index 73b857a90..6d7fd92ab 100644 --- a/src/audio_core/hle/pipe.h +++ b/src/audio_core/hle/pipe.h @@ -15,7 +15,12 @@ namespace HLE { /// Reset the pipes by setting pipe positions back to the beginning. void ResetPipes(); -enum class DspPipe { Debug = 0, Dma = 1, Audio = 2, Binary = 3 }; +enum class DspPipe { + Debug = 0, + Dma = 1, + Audio = 2, + Binary = 3, +}; constexpr size_t NUM_DSP_PIPE = 8; /** @@ -46,7 +51,12 @@ size_t GetPipeReadableSize(DspPipe pipe_number); */ void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer); -enum class DspState { Off, On, Sleeping }; +enum class DspState { + Off, + On, + Sleeping, +}; + /// Get the state of the DSP DspState GetDspState(); diff --git a/src/audio_core/hle/source.cpp b/src/audio_core/hle/source.cpp index fad0ce2ad..249acc449 100644 --- a/src/audio_core/hle/source.cpp +++ b/src/audio_core/hle/source.cpp @@ -163,16 +163,18 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, if (config.embedded_buffer_dirty) { config.embedded_buffer_dirty.Assign(0); - state.input_queue.emplace(Buffer{config.physical_address, - config.length, - static_cast<u8>(config.adpcm_ps), - {config.adpcm_yn[0], config.adpcm_yn[1]}, - config.adpcm_dirty.ToBool(), - config.is_looping.ToBool(), - config.buffer_id, - state.mono_or_stereo, - state.format, - false}); + state.input_queue.emplace(Buffer{ + config.physical_address, + config.length, + static_cast<u8>(config.adpcm_ps), + {config.adpcm_yn[0], config.adpcm_yn[1]}, + config.adpcm_dirty.ToBool(), + config.is_looping.ToBool(), + config.buffer_id, + state.mono_or_stereo, + state.format, + false, + }); LOG_TRACE(Audio_DSP, "enqueuing embedded addr=0x%08x len=%u id=%hu", config.physical_address, config.length, config.buffer_id); } @@ -182,16 +184,18 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, for (size_t i = 0; i < 4; i++) { if (config.buffers_dirty & (1 << i)) { const auto& b = config.buffers[i]; - state.input_queue.emplace(Buffer{b.physical_address, - b.length, - static_cast<u8>(b.adpcm_ps), - {b.adpcm_yn[0], b.adpcm_yn[1]}, - b.adpcm_dirty != 0, - b.is_looping != 0, - b.buffer_id, - state.mono_or_stereo, - state.format, - true}); + state.input_queue.emplace(Buffer{ + b.physical_address, + b.length, + static_cast<u8>(b.adpcm_ps), + {b.adpcm_yn[0], b.adpcm_yn[1]}, + b.adpcm_dirty != 0, + b.is_looping != 0, + b.buffer_id, + state.mono_or_stereo, + state.format, + true, + }); LOG_TRACE(Audio_DSP, "enqueuing queued %zu addr=0x%08x len=%u id=%hu", i, b.physical_address, b.length, b.buffer_id); } diff --git a/src/audio_core/interpolate.cpp b/src/audio_core/interpolate.cpp index 7751c545d..cb1c58a67 100644 --- a/src/audio_core/interpolate.cpp +++ b/src/audio_core/interpolate.cpp @@ -71,15 +71,17 @@ StereoBuffer16 None(State& state, const StereoBuffer16& input, float rate_multip StereoBuffer16 Linear(State& state, const StereoBuffer16& input, float rate_multiplier) { // Note on accuracy: Some values that this produces are +/- 1 from the actual firmware. - return StepOverSamples(state, input, rate_multiplier, [](u64 fraction, const auto& x0, - const auto& x1, const auto& x2) { - // This is a saturated subtraction. (Verified by black-box fuzzing.) - s64 delta0 = MathUtil::Clamp<s64>(x1[0] - x0[0], -32768, 32767); - s64 delta1 = MathUtil::Clamp<s64>(x1[1] - x0[1], -32768, 32767); - - return std::array<s16, 2>{static_cast<s16>(x0[0] + fraction * delta0 / scale_factor), - static_cast<s16>(x0[1] + fraction * delta1 / scale_factor)}; - }); + return StepOverSamples(state, input, rate_multiplier, + [](u64 fraction, const auto& x0, const auto& x1, const auto& x2) { + // This is a saturated subtraction. (Verified by black-box fuzzing.) + s64 delta0 = MathUtil::Clamp<s64>(x1[0] - x0[0], -32768, 32767); + s64 delta1 = MathUtil::Clamp<s64>(x1[1] - x0[1], -32768, 32767); + + return std::array<s16, 2>{ + static_cast<s16>(x0[0] + fraction * delta0 / scale_factor), + static_cast<s16>(x0[1] + fraction * delta1 / scale_factor), + }; + }); } } // namespace AudioInterp diff --git a/src/audio_core/interpolate.h b/src/audio_core/interpolate.h index 99e5b9657..2d2e60311 100644 --- a/src/audio_core/interpolate.h +++ b/src/audio_core/interpolate.h @@ -25,7 +25,7 @@ struct State { * @param input Input buffer. * @param rate_multiplier Stretch factor. Must be a positive non-zero value. * rate_multiplier > 1.0 performs decimation and rate_multipler < 1.0 - * performs upsampling. + * performs upsampling. * @return The resampled audio buffer. */ StereoBuffer16 None(State& state, const StereoBuffer16& input, float rate_multiplier); @@ -35,7 +35,7 @@ StereoBuffer16 None(State& state, const StereoBuffer16& input, float rate_multip * @param input Input buffer. * @param rate_multiplier Stretch factor. Must be a positive non-zero value. * rate_multiplier > 1.0 performs decimation and rate_multipler < 1.0 - * performs upsampling. + * performs upsampling. * @return The resampled audio buffer. */ StereoBuffer16 Linear(State& state, const StereoBuffer16& input, float rate_multiplier); diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h index b82cd3b9a..9931c4778 100644 --- a/src/audio_core/null_sink.h +++ b/src/audio_core/null_sink.h @@ -19,8 +19,7 @@ public: return native_sample_rate; } - void EnqueueSamples(const s16*, size_t) override { - } + void EnqueueSamples(const s16*, size_t) override {} size_t SamplesInQueue() const override { return 0; diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h index c938e87d2..f5ce55a6b 100644 --- a/src/audio_core/sink.h +++ b/src/audio_core/sink.h @@ -12,8 +12,8 @@ namespace AudioCore { /** * This class is an interface for an audio sink. An audio sink accepts samples in stereo signed - * PCM16 format to be output. - * Sinks *do not* handle resampling and expect the correct sample rate. They are dumb outputs. + * PCM16 format to be output. Sinks *do not* handle resampling and expect the correct sample rate. + * They are dumb outputs. */ class Sink { public: diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h index 34110c97a..4b30cf835 100644 --- a/src/audio_core/sink_details.h +++ b/src/audio_core/sink_details.h @@ -14,8 +14,7 @@ class Sink; struct SinkDetails { SinkDetails(const char* id_, std::function<std::unique_ptr<Sink>()> factory_) - : id(id_), factory(factory_) { - } + : id(id_), factory(factory_) {} /// Name for this sink. const char* id; |