From 59c83ea212849ed0ea1ed8a70057f6bcc3041e6b Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Thu, 4 Jul 2024 20:18:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BB=B6=E8=BF=9F=E8=A1=A5=E5=81=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/audio/misc/circular_audio_buffer.h | 250 ++++++++++++----------- core/audio/mixer/latency_compensator.cpp | 20 +- core/audio/mixer/latency_compensator.h | 4 +- core/audio/mixer/mixer.cpp | 4 +- core/audio/mixer/mixer_track.cpp | 10 +- core/audio/mixer/mixer_track.h | 10 +- 6 files changed, 151 insertions(+), 147 deletions(-) diff --git a/core/audio/misc/circular_audio_buffer.h b/core/audio/misc/circular_audio_buffer.h index 9ee981a..a469384 100644 --- a/core/audio/misc/circular_audio_buffer.h +++ b/core/audio/misc/circular_audio_buffer.h @@ -22,10 +22,10 @@ template class circular_audio_buffer { private: - std::vector InternalBuffer; - uint32_t Capacity; - std::atomic ReadCounter; - std::atomic WriteCounter; + std::vector internal_buffer_; + uint32_t capacity_; + std::atomic read_counter_; + std::atomic write_counter_; public: circular_audio_buffer() { @@ -37,171 +37,171 @@ public: } circular_audio_buffer& operator=(const circular_audio_buffer& InOther) { - InternalBuffer = InOther.InternalBuffer; - Capacity = InOther.Capacity; - ReadCounter.store(InOther.ReadCounter); - WriteCounter.store(InOther.WriteCounter); + internal_buffer_ = InOther.internal_buffer_; + capacity_ = InOther.capacity_; + read_counter_.store(InOther.read_counter_); + write_counter_.store(InOther.write_counter_); return *this; } - explicit circular_audio_buffer(uint32_t InCapacity) { - set_capacity(InCapacity); + explicit circular_audio_buffer(uint32_t in_capacity) { + set_capacity(in_capacity); } // move - circular_audio_buffer(circular_audio_buffer&& InOther) noexcept { - InternalBuffer = std::move(InOther.InternalBuffer); - Capacity = InOther.Capacity; - ReadCounter.store(InOther.ReadCounter); - WriteCounter.store(InOther.WriteCounter); + circular_audio_buffer(circular_audio_buffer&& in_other) noexcept { + internal_buffer_ = std::move(in_other.internal_buffer_); + capacity_ = in_other.capacity_; + read_counter_.store(in_other.read_counter_); + write_counter_.store(in_other.write_counter_); - InOther.Capacity = 0; - InOther.ReadCounter = 0; - InOther.WriteCounter = 0; + in_other.capacity_ = 0; + in_other.read_counter_ = 0; + in_other.write_counter_ = 0; } - void reset(uint32_t InCapacity = 0) { - set_capacity(InCapacity); + void reset(uint32_t in_capacity = 0) { + set_capacity(in_capacity); } - void set_capacity(uint32_t InCapacity) { - if (InCapacity >= 2147483647) { spdlog::error("Max capacity for this buffer is 2,147,483,647 samples. Otherwise our index arithmetic will not work."); throw std::runtime_error(fmt::format("Max capacity for this buffer is 2,147,483,647 samples. Otherwise our index arithmetic will not work.")); }; + void set_capacity(uint32_t in_capacity) { + if (in_capacity >= 2147483647) { spdlog::error("Max capacity for this buffer is 2,147,483,647 samples. Otherwise our index arithmetic will not work."); throw std::runtime_error(fmt::format("Max capacity for this buffer is 2,147,483,647 samples. Otherwise our index arithmetic will not work.")); }; - Capacity = InCapacity + 1; - ReadCounter = 0; - WriteCounter = 0; - InternalBuffer.clear(); - InternalBuffer.resize(Capacity); + capacity_ = in_capacity + 1; + read_counter_ = 0; + write_counter_ = 0; + internal_buffer_.clear(); + internal_buffer_.resize(capacity_); } /** Reserve capacity. * - * @param InMinimumCapacity - Minimum capacity of circular buffer. - * @param bRetainExistingSamples - If true, existing samples in the buffer will be retained. If false, they are discarded. + * @param in_minimum_capacity - Minimum capacity of circular buffer. + * @param retain_existing_samples - If true, existing samples in the buffer will be retained. If false, they are discarded. */ - void reserve(uint32_t InMinimumCapacity, bool bRetainExistingSamples) { - if (Capacity <= InMinimumCapacity) { - uint32_t NewCapacity = InMinimumCapacity + 1; + void reserve(uint32_t in_minimum_capacity, bool retain_existing_samples) { + if (capacity_ <= in_minimum_capacity) { + uint32_t new_capacity = in_minimum_capacity + 1; - checkf(NewCapacity < (uint32_t)INT32_MAX, - "Max capacity overflow. Requested {}. Maximum allowed {}", NewCapacity, - INT32_MAX); + checkf(new_capacity < (uint32_t)INT32_MAX, + "Max capacity overflow. Requested {}. Maximum allowed {}", new_capacity, + INT32_MAX); - uint32_t NumToAdd = NewCapacity - Capacity; - InternalBuffer.AddZeroed(NumToAdd); - Capacity = NewCapacity; + uint32_t num_to_add = new_capacity - capacity_; + internal_buffer_.AddZeroed(num_to_add); + capacity_ = new_capacity; } - if (!bRetainExistingSamples) { - ReadCounter = 0; - WriteCounter = 0; + if (!retain_existing_samples) { + read_counter_ = 0; + write_counter_ = 0; } } /** Push an array of values into circular buffer. */ - int32_t push(const std::vector& InBuffer) { - return push(InBuffer.data(), InBuffer.size()); + int32_t push(const std::vector& in_buffer) { + return push(in_buffer.data(), in_buffer.size()); } // Pushes some amount of samples into this circular buffer. // Returns the amount of samples written. // This can only be used for trivially copyable types. - int32_t push(const SampleType* InBuffer, uint32_t NumSamples) { - SampleType* DestBuffer = InternalBuffer.data(); - const uint32_t ReadIndex = ReadCounter; - const uint32_t WriteIndex = WriteCounter; + int32_t push(const SampleType* in_buffer, uint32_t num_samples) { + SampleType* dest_buffer = internal_buffer_.data(); + const uint32_t read_index = read_counter_; + const uint32_t write_index = write_counter_; - int32_t NumToCopy = std::min(NumSamples, remainder()); - const int32_t NumToWrite = std::min(NumToCopy, Capacity - WriteIndex); + int32_t num_to_copy = std::min(num_samples, remainder()); + const int32_t num_to_write = std::min(num_to_copy, capacity_ - write_index); - memcpy(&DestBuffer[WriteIndex], InBuffer, NumToWrite * sizeof(SampleType)); - memcpy(&DestBuffer[0], &InBuffer[NumToWrite], (NumToCopy - NumToWrite) * sizeof(SampleType)); + memcpy(&dest_buffer[write_index], in_buffer, num_to_write * sizeof(SampleType)); + memcpy(&dest_buffer[0], &in_buffer[num_to_write], (num_to_copy - num_to_write) * sizeof(SampleType)); - WriteCounter = (WriteIndex + NumToCopy) % Capacity; + write_counter_ = (write_index + num_to_copy) % capacity_; - return NumToCopy; + return num_to_copy; } // Pushes some amount of zeros into the circular buffer. // Useful when acting as a blocked, mono/interleaved delay line - int32_t push_zeros(uint32_t NumSamplesOfZeros) { - SampleType* DestBuffer = InternalBuffer.data(); - const uint32_t ReadIndex = ReadCounter; - const uint32_t WriteIndex = WriteCounter; + int32_t push_zeros(uint32_t num_samples_of_zeros) { + SampleType* dest_buffer = internal_buffer_.data(); + const uint32_t read_index = read_counter_; + const uint32_t write_index = write_counter_; - int32_t NumToZeroEnd = std::min(NumSamplesOfZeros, remainder()); - const int32_t NumToZeroBegin = std::min(NumToZeroEnd, Capacity - WriteIndex); + int32_t num_to_zero_end = std::min(num_samples_of_zeros, remainder()); + const int32_t num_to_zero_begin = std::min(num_to_zero_end, capacity_ - write_index); - memset(&DestBuffer[WriteIndex], 0, NumToZeroBegin * sizeof(SampleType)); - memset(&DestBuffer[0], 0, (NumToZeroEnd - NumToZeroBegin) * sizeof(SampleType)); + memset(&dest_buffer[write_index], 0, num_to_zero_begin * sizeof(SampleType)); + memset(&dest_buffer[0], 0, (num_to_zero_end - num_to_zero_begin) * sizeof(SampleType)); - WriteCounter = (WriteIndex + NumToZeroEnd) % Capacity; + write_counter_ = (write_index + num_to_zero_end) % capacity_; - return NumToZeroEnd; + return num_to_zero_end; } // Push a single sample onto this buffer. // Returns false if the buffer is full. - bool push(const SampleType& InElement) { + bool push(const SampleType& in_element) { if (remainder() == 0) { return false; } else { - SampleType* DestBuffer = InternalBuffer.data(); - const uint32_t ReadIndex = ReadCounter; - const uint32_t WriteIndex = WriteCounter; + SampleType* dest_buffer = internal_buffer_.data(); + const uint32_t read_index = read_counter_; + const uint32_t write_index = write_counter_; - DestBuffer[WriteIndex] = InElement; + dest_buffer[write_index] = in_element; - WriteCounter = (WriteIndex + 1) % Capacity; + write_counter_ = (write_index + 1) % capacity_; return true; } } - bool push(SampleType&& InElement) { + bool push(SampleType&& in_element) { if (remainder() == 0) { return false; } else { - SampleType* DestBuffer = InternalBuffer.data(); - const uint32_t ReadIndex = ReadCounter; - const uint32_t WriteIndex = WriteCounter; + SampleType* dest_buffer = internal_buffer_.data(); + const uint32_t read_index = read_counter_; + const uint32_t write_counter = write_counter_; - DestBuffer[WriteIndex] = MoveTemp(InElement); + dest_buffer[write_counter] = MoveTemp(in_element); - WriteCounter = (WriteIndex + 1) % Capacity; + write_counter_ = (write_counter + 1) % capacity_; return true; } } // Same as Pop(), but does not increment the read counter. - int32_t peek(SampleType* OutBuffer, uint32_t NumSamples) const { - const SampleType* SrcBuffer = InternalBuffer.data(); - const uint32_t ReadIndex = ReadCounter; - const uint32_t WriteIndex = WriteCounter; + int32_t peek(SampleType* out_buffer, uint32_t num_samples) const { + const SampleType* src_buffer = internal_buffer_.data(); + const uint32_t read_index = read_counter_; + const uint32_t write_index = write_counter_; - int32_t NumToCopy = std::min(NumSamples, num()); + int32_t num_to_copy = std::min(num_samples, num()); - const int32_t NumRead = std::min(NumToCopy, Capacity - ReadIndex); - memcpy(OutBuffer, &SrcBuffer[ReadIndex], NumRead * sizeof(SampleType)); + const int32_t num_read = std::min(num_to_copy, capacity_ - read_index); + memcpy(out_buffer, &src_buffer[read_index], num_read * sizeof(SampleType)); - memcpy(&OutBuffer[NumRead], &SrcBuffer[0], (NumToCopy - NumRead) * sizeof(SampleType)); + memcpy(&out_buffer[num_read], &src_buffer[0], (num_to_copy - num_read) * sizeof(SampleType)); - check(NumSamples < ((uint32_t)INT32_MAX)); + check(num_samples < ((uint32_t)INT32_MAX)); - return NumToCopy; + return num_to_copy; } // Peeks a single element. // returns false if the element is empty. - bool peek(SampleType& OutElement) const { + bool peek(SampleType& out_element) const { if (num() == 0) { return false; } else { - SampleType* SrcBuffer = InternalBuffer.data(); - const uint32_t ReadIndex = ReadCounter; + SampleType* src_buffer = internal_buffer_.data(); + const uint32_t read_index = read_counter_; - OutElement = SrcBuffer[ReadIndex]; + out_element = src_buffer[read_index]; return true; } @@ -209,25 +209,25 @@ public: // Pops some amount of samples into this circular buffer. // Returns the amount of samples read. - int32_t pop(SampleType* OutBuffer, uint32_t NumSamples) { - int32_t NumSamplesRead = peek(OutBuffer, NumSamples); - check(NumSamples < ((uint32_t)INT32_MAX)); + int32_t pop(SampleType* out_buffer, uint32_t num_samples) { + int32_t num_samples_read = peek(out_buffer, num_samples); + check(num_samples < ((uint32_t)INT32_MAX)); - ReadCounter = (ReadCounter + NumSamplesRead) % Capacity; + read_counter_ = (read_counter_ + num_samples_read) % capacity_; - return NumSamplesRead; + return num_samples_read; } // Pops some amount of samples into this circular buffer. // Returns the amount of samples read. - int32_t pop(uint32_t NumSamples) { - check(NumSamples < ((uint32_t)INT32_MAX)); + int32_t pop(uint32_t num_samples) { + check(num_samples < ((uint32_t)INT32_MAX)); - int32_t NumSamplesRead = std::min(NumSamples, num()); + int32_t num_samples_read = std::min(num_samples, num()); - ReadCounter = (ReadCounter + NumSamplesRead) % Capacity; + read_counter_ = (read_counter_ + num_samples_read) % capacity_; - return NumSamplesRead; + return num_samples_read; } // Pops a single element. @@ -236,55 +236,63 @@ public: // Calling this when the buffer is empty is considered a fatal error. check(Num() > 0); - SampleType* SrcBuffer = InternalBuffer.data(); - const uint32_t ReadIndex = ReadCounter; + SampleType* src_buffer = internal_buffer_.data(); + const uint32_t read_index = read_counter_; - SampleType PoppedValue = std::move(InternalBuffer[ReadIndex]); - ReadCounter = (ReadCounter + 1) % Capacity; - return PoppedValue; + SampleType popped_value = std::move(internal_buffer_[read_index]); + read_counter_ = (read_counter_ + 1) % capacity_; + return popped_value; } + SampleType* get_header() { + // Calling this when the buffer is empty is considered a fatal error. + check(Num() > 0); + + // 根据read_counter_获取当前的header + return &internal_buffer_[read_counter_]; + } + // When called, seeks the read or write cursor to only retain either the NumSamples latest data // (if bRetainOldestSamples is false) or the NumSamples oldest data (if bRetainOldestSamples is true) // in the buffer. Cannot be used to increase the capacity of this buffer. - void set_num(uint32_t NumSamples, bool bRetainOldestSamples = false) { - check(NumSamples < Capacity); + void set_num(uint32_t num_samples, bool retain_oldest_samples = false) { + check(num_samples < capacity_); - if (bRetainOldestSamples) { - WriteCounter = (ReadCounter + NumSamples) % Capacity; + if (retain_oldest_samples) { + write_counter_ = (read_counter_ + num_samples) % capacity_; } else { - int64_t ReadCounterNum = ((int32_t) WriteCounter) - ((int32_t) NumSamples); - if (ReadCounterNum < 0) { - ReadCounterNum = Capacity + ReadCounterNum; + int64_t read_counter_num = ((int32_t) write_counter_) - ((int32_t) num_samples); + if (read_counter_num < 0) { + read_counter_num = capacity_ + read_counter_num; } - ReadCounter = ReadCounterNum; + read_counter_ = read_counter_num; } } // Get number of samples that can be popped off of the buffer. uint32_t num() const { - const int32_t ReadIndex = ReadCounter; - const int32_t WriteIndex = WriteCounter; + const int32_t read_index = read_counter_; + const int32_t write_index = write_counter_; - if (WriteIndex >= ReadIndex) { - return WriteIndex - ReadIndex; + if (write_index >= read_index) { + return write_index - read_index; } else { - return Capacity - ReadIndex + WriteIndex; + return capacity_ - read_index + write_index; } } // Get the current capacity of the buffer uint32_t get_capacity() const { - return Capacity; + return capacity_; } // Get number of samples that can be pushed onto the buffer before it is full. uint32_t remainder() const { - const uint32_t ReadIndex = ReadCounter; - const uint32_t WriteIndex = WriteCounter; + const uint32_t read_index = read_counter_; + const uint32_t write_index = write_counter_; - return (Capacity - 1 - WriteIndex + ReadIndex) % Capacity; + return (capacity_ - 1 - write_index + read_index) % capacity_; } }; diff --git a/core/audio/mixer/latency_compensator.cpp b/core/audio/mixer/latency_compensator.cpp index 899a7f4..9ba2d5d 100644 --- a/core/audio/mixer/latency_compensator.cpp +++ b/core/audio/mixer/latency_compensator.cpp @@ -18,9 +18,13 @@ latency_compensator::~latency_compensator() { void latency_compensator::init() { const uint32_t channel_count = g_audio_device_manager.get_output_channel_count(); internal_buffer.resize(channel_count); + ui_buffers.resize(channel_count); uint32_t block_size = g_audio_device_manager.get_buffer_size(); resize(block_size); + for (auto& buffer : ui_buffers) { + buffer.set_capacity(block_size * 2); + } } void latency_compensator::set_latency(int32_t in_latency_offset) { @@ -51,30 +55,32 @@ void latency_compensator::push(audio_buffer& in_buffer) { void latency_compensator::pop(uint64_t delta_sample, circular_buffer_vector_type& out_buffer) { std::vector temp_buffer(delta_sample); - for (auto buffer : std::views::zip(internal_buffer, out_buffer)) { - auto& [internal, target_buffer] = buffer; + for (auto buffer : std::views::zip(internal_buffer, ui_buffers, out_buffer)) { + auto& [internal, ui_buffer, target_buffer] = buffer; internal.pop(temp_buffer.data(), delta_sample); target_buffer.push(temp_buffer); + ui_buffer.push(temp_buffer); memset(temp_buffer.data(), 0, delta_sample * sizeof(sample_t)); } } void latency_compensator::pop(uint64_t delta_smaple, audio_buffer& out_buffer) { - for (auto buffer : std::views::zip(internal_buffer, out_buffer.get_headers_vector())) { - auto& [internal, target_buffer] = buffer; + for (auto buffer : std::views::zip(internal_buffer, ui_buffers, out_buffer.get_headers_vector())) { + auto& [internal, ui_buffer, target_buffer] = buffer; internal.pop(target_buffer, delta_smaple); + ui_buffer.push(target_buffer, delta_smaple); } } void latency_compensator::update_buffer(int32_t min_latency, int32_t max_latency) { // 根据全局最大延迟计算需要的buffer大小 const uint32_t block_size = g_audio_device_manager.get_buffer_size(); - const auto& buffer_size = get_real_latency() - max_latency; + const auto& buffer_size = std::max(0, max_latency - get_real_latency()); - const uint32_t block_num = buffer_size / block_size + 1; + const int32_t block_num = buffer_size / block_size + 1; resize(block_num * block_size); - const auto& buffer_latency = (get_real_latency() - min_latency) + max_latency; // 计算需要的buffer大小 + const auto& buffer_latency = max_latency - (get_real_latency() - min_latency); // 计算需要的buffer大小 push_zeros(buffer_latency); } diff --git a/core/audio/mixer/latency_compensator.h b/core/audio/mixer/latency_compensator.h index 22f92ce..8732b96 100644 --- a/core/audio/mixer/latency_compensator.h +++ b/core/audio/mixer/latency_compensator.h @@ -6,7 +6,7 @@ #include "audio/misc/circular_audio_buffer.h" #include "misc/delegates.h" -inline static multicast_delegate<> on_latency_offset_changed; +inline multicast_delegate<> on_latency_offset_changed; class latency_compensator { public: @@ -33,6 +33,8 @@ public: [[nodiscard]] int32_t get_real_latency() const { return latency_ + user_latency_; } [[nodiscard]] circular_buffer_vector_type& get_internal_buffer() { return internal_buffer; } + + circular_buffer_vector_type ui_buffers; protected: void resize(uint32_t block_size) { for (auto& channel : internal_buffer) { diff --git a/core/audio/mixer/mixer.cpp b/core/audio/mixer/mixer.cpp index 1edf6a6..b06d74f 100644 --- a/core/audio/mixer/mixer.cpp +++ b/core/audio/mixer/mixer.cpp @@ -235,9 +235,9 @@ void mixer::on_mixer_latency_changed() { max_latency = std::max(max_latency, track->get_real_latency()); min_latency = std::min(min_latency, track->get_real_latency()); } - int32_t latency = max_latency - min_latency; - for (mixer_track* track : tracks_) { + for (size_t i = 1; i < tracks_.size(); i++) { + mixer_track* track = tracks_[i]; track->compensator_.update_buffer(min_latency, max_latency); } } diff --git a/core/audio/mixer/mixer_track.cpp b/core/audio/mixer/mixer_track.cpp index e7b15b2..f205edc 100644 --- a/core/audio/mixer/mixer_track.cpp +++ b/core/audio/mixer/mixer_track.cpp @@ -18,9 +18,6 @@ void mixer_track::init() { const uint32_t channel_count = g_audio_device_manager.get_output_channel_count(); buffer_.resize(channel_count, g_audio_device_manager.get_buffer_size()); temp_mix_buffer_.resize(buffer_.get_num_channels(), g_audio_device_manager.get_buffer_size()); - for (int i = 0; i < channel_count; ++i) { - ui_buffers->emplace_back(g_audio_device_manager.get_buffer_size() * 2); - } channel_interface_ = new mixer_channel_interface(this); compensator_.init(); @@ -74,11 +71,6 @@ void mixer_track::process(uint32_t in_frames) { void mixer_track::post_process(uint32_t in_frames) { buffer_.multiple(get_volume()); - // TODO ui_buffer需要在compensator后面 - for (int i = 0; i < buffer_.get_num_channels(); ++i) { - auto& ui_buffer = (*ui_buffers)[i]; - ui_buffer.push(buffer_.get_headers()[i], in_frames); - } } void mixer_track::on_latency_changed(int32_t in_latency) { @@ -102,7 +94,7 @@ std::string instrument_track::get_name() const { } void instrument_track::on_latency_changed(int32_t in_latency) { - int32_t latency = in_latency; + int32_t latency = 0; for (const auto effect: effects) { latency += effect->get_latency(); } diff --git a/core/audio/mixer/mixer_track.h b/core/audio/mixer/mixer_track.h index f0507f5..f8daf1e 100644 --- a/core/audio/mixer/mixer_track.h +++ b/core/audio/mixer/mixer_track.h @@ -28,9 +28,7 @@ struct mixer_track_link { class CORE_API mixer_track { friend class mixer; public: - explicit mixer_track(mixer_track_type in_type) : type_(in_type), id_(gen_uid()) { - ui_buffers = std::make_shared(); - } + explicit mixer_track(mixer_track_type in_type) : type_(in_type), id_(gen_uid()) {} [[nodiscard]] uint64_t get_uid() const { return id_; } virtual ~mixer_track(); @@ -61,6 +59,7 @@ public: [[nodiscard]] int32_t get_user_latency() const { return compensator_.get_user_latency(); } [[nodiscard]] int32_t get_real_latency() const { return compensator_.get_real_latency(); } void set_user_latency(int32_t in_latency) { compensator_.set_latency(in_latency); } + [[nodiscard]] circular_buffer_vector_type& get_ui_buffers() { return compensator_.ui_buffers; } [[nodiscard]] std::string get_imgui_id() const { return get_name() + "##" + std::to_string(id_); @@ -68,12 +67,9 @@ public: std::vector effects{}; std::vector children{}; - - // UI - std::shared_ptr ui_buffers; protected: virtual void on_latency_changed(int32_t in_latency); - latency_compensator compensator_; + latency_compensator compensator_; private: audio_buffer buffer_; audio_buffer temp_mix_buffer_;