From 4f3dc015f7d3b482353e731cbc4a507737a5fd79 Mon Sep 17 00:00:00 2001 From: luocai Date: Wed, 4 Sep 2024 20:17:15 +0800 Subject: [PATCH] update code. --- Record/Player.cpp | 29 +++++++++++++++----- Record/RkAudio.cpp | 6 ++++- Record/SpeexDsp.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++-- Record/SpeexDsp.h | 14 +++++++--- Record/main.cpp | 7 +++++ Record/main.h | 7 +++++ 6 files changed, 116 insertions(+), 13 deletions(-) diff --git a/Record/Player.cpp b/Record/Player.cpp index 6527982..29a0dcd 100644 --- a/Record/Player.cpp +++ b/Record/Player.cpp @@ -12,31 +12,47 @@ void PlayerTask::setPath(const std::string &path) { } } +void PlayerTask::setChannels(int channels) { + if (m_channels != channels) { + m_channels = channels; + } +} + /* ffmpeg将一个1通道mp3文件,转换为 2通道,16bit,16000采样率的pcm文件,但是左通道数据为静音 -ffmpeg -i 20200316_1900.mp3 -ac 2 -ar 16000 -filter_complex "[0:a]pan=stereo|c0=0*c0|c1=1*c0[a]" -map "[a]" -f s16le -acodec pcm_s16le 20200316_1900.pcm +ffmpeg -i 20200316_1900.mp3 -ac 2 -ar 16000 -filter_complex "[0:a]pan=stereo|c0=0*c0|c1=1*c0[a]" -map "[a]" -f s16le -acodec pcm_s16le +20200316_1900.pcm ffmpeg将一个1通道mp3文件,转换为 2通道,16bit,16000采样率的pcm文件,但是右通道数据为静音 -ffmpeg -i 20200316_1900.mp3 -ac 2 -ar 16000 -filter_complex "[0:a]pan=stereo|c0=1*c0|c1=0*c0[a]" -map "[a]" -f s16le -acodec pcm_s16le 20200316_1900.pcm +ffmpeg -i 20200316_1900.mp3 -ac 2 -ar 16000 -filter_complex "[0:a]pan=stereo|c0=1*c0|c1=0*c0[a]" -map "[a]" -f s16le -acodec pcm_s16le +20200316_1900.pcm +ffmpeg -i 20200316_1900.mp3 -ac 2 -ar 16000 -f s16le -acodec pcm_s16le 20200316_1900_2ch.pcm +ffmpeg -i 20200316_1900.mp3 -ac 1 -ar 16000 -f s16le -acodec pcm_s16le 20200316_1900_1ch.pcm +20200316_1900.mp3 +./Record --play --channels=1 --path=/sdcard/data/20200316_1900_1ch.pcm +./Record --play --path=/sdcard/data/20200316_1900_2ch.pcm +./Record --play --path=/sdcard/data/20200316_1900_left_silence.pcm +./Record --play --path=/sdcard/data/20200316_1900_right_silense.pcm +20240904160913.pcm */ - // ./Record --play --path=/sdcard/data/20240904160913.pcm void PlayerTask::run() { using namespace Amass; RkAudio::Format format; - format.channels = 2; + format.channels = m_channels; format.period = 64; m_output = std::make_shared(); if (!m_output->open(sizeof(uint16_t), format.sampleRate, format.channels, format.period, false)) { LOG(error) << "audio output open failed."; return; } + m_buffer.resize(m_channels*sizeof(int16_t)*16* format.period); play(); } @@ -47,10 +63,9 @@ void PlayerTask::play() { LOG(info) << "play finished"; return; } - char buffer[2 * sizeof(int16_t) * 16 * 64]; - m_ifs->read(buffer, sizeof(buffer)); + m_ifs->read(m_buffer.data(), m_buffer.size()); auto readedSize = m_ifs->gcount(); - m_output->write(reinterpret_cast(buffer), readedSize); + m_output->write(reinterpret_cast(m_buffer.data()), readedSize); boost::asio::post(*ioConext->ioContext(), [this]() { play(); }); } \ No newline at end of file diff --git a/Record/RkAudio.cpp b/Record/RkAudio.cpp index bc6a2f6..c4539ed 100644 --- a/Record/RkAudio.cpp +++ b/Record/RkAudio.cpp @@ -151,7 +151,11 @@ bool Output::open(uint32_t sampleSize, uint32_t sampleRate, uint32_t channels, u parameter.u32Channels = channels; RK_MPI_AO_SetChnAttr(m_channel, ¶meter); - RK_MPI_AO_EnableChn(m_channel); + auto status = RK_MPI_AO_EnableChn(m_channel); + if (status != 0) { + LOG(error) << "RK_MPI_AO_EnableChn() failed, status: " << status; + return false; + } if (enableVqe) { AO_VQE_CONFIG_S config = {0}; diff --git a/Record/SpeexDsp.cpp b/Record/SpeexDsp.cpp index 1e399f9..800a4ba 100644 --- a/Record/SpeexDsp.cpp +++ b/Record/SpeexDsp.cpp @@ -2,9 +2,53 @@ #include #include +SpeexDsp::~SpeexDsp() { + close(); +} + + + +void SpeexDsp::start(int sampleRate, int channels, int period) { + close(); + int frameSize = sampleRate * period / 1000; // 10-20 ms + int filterLength = sampleRate * 500 / 1000; // 100-500 ms + m_echoState = speex_echo_state_init_mc(frameSize, filterLength, channels, channels); + speex_echo_ctl(m_echoState, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate); + + m_preprocessState = speex_preprocess_state_init(frameSize, sampleRate); + speex_preprocess_ctl(m_preprocessState, SPEEX_PREPROCESS_SET_ECHO_STATE, m_echoState); + + int32_t noiseSuppress = -25, i = 1; + speex_preprocess_ctl(m_preprocessState, SPEEX_PREPROCESS_SET_DENOISE, &i); + speex_preprocess_ctl(m_preprocessState, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &noiseSuppress); + + i = 0; + speex_preprocess_ctl(m_preprocessState, SPEEX_PREPROCESS_SET_AGC, &i); + i = sampleRate; + speex_preprocess_ctl(m_preprocessState, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i); + i = 0; + speex_preprocess_ctl(m_preprocessState, SPEEX_PREPROCESS_SET_DEREVERB, &i); + float f = .0; + speex_preprocess_ctl(m_preprocessState, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); + f = .0; + speex_preprocess_ctl(m_preprocessState, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); +} + +void SpeexDsp::close() { + if (m_preprocessState != nullptr) { + speex_preprocess_state_destroy(m_preprocessState); + m_preprocessState = nullptr; + } + + if (m_echoState != nullptr) { + speex_echo_state_destroy(m_echoState); + m_echoState = nullptr; + } +} + void SpeexDsp::reset() { - if (m_state != nullptr) { - speex_echo_state_reset(m_state); + if (m_echoState != nullptr) { + speex_echo_state_reset(m_echoState); } } @@ -13,3 +57,21 @@ void SpeexDsp::preprocess(int16_t *pcm) { speex_preprocess_run(m_preprocessState, pcm); } } + +void SpeexDsp::echoPlayback(const int16_t *play) { + if (m_echoState != nullptr) { + speex_echo_playback(m_echoState, play); + } +} + +void SpeexDsp::echoCapture(const int16_t *record, int16_t *out) { + if (m_echoState != nullptr) { + speex_echo_capture(m_echoState, record, out); + } +} + +void SpeexDsp::echoCancellation(const int16_t *record, const int16_t *play, int16_t *out) { + if (m_echoState != nullptr) { + speex_echo_cancellation(m_echoState, record, play, out); + } +} diff --git a/Record/SpeexDsp.h b/Record/SpeexDsp.h index a18d21c..18f2610 100644 --- a/Record/SpeexDsp.h +++ b/Record/SpeexDsp.h @@ -8,12 +8,20 @@ typedef struct SpeexPreprocessState_ SpeexPreprocessState; class SpeexDsp { public: -void preprocess(int16_t *pcm); + ~SpeexDsp(); + void start(int sampleRate, int channels, int period); + void close(); + void preprocess(int16_t *pcm); + + void echoCancellation(const int16_t *record, const int16_t *play, int16_t *out); + + void echoPlayback(const int16_t *play); + void echoCapture(const int16_t *record, int16_t *out); void reset(); private: - SpeexEchoState *m_state = nullptr; - SpeexPreprocessState *m_preprocessState=nullptr; + SpeexEchoState *m_echoState = nullptr; + SpeexPreprocessState *m_preprocessState = nullptr; }; #endif // __SPEEXDSP_H__ \ No newline at end of file diff --git a/Record/main.cpp b/Record/main.cpp index 5e7884f..e6a8497 100644 --- a/Record/main.cpp +++ b/Record/main.cpp @@ -78,7 +78,14 @@ int main(int argc, char **argv) { if (variablesMap.count("path")) { path = variablesMap["path"].as(); } + + int channels = 2; + if (variablesMap.count("channels")) { + channels = variablesMap["channels"].as(); + } + auto t = std::make_shared(); + t->setChannels(channels); t->setPath(path); task = std::dynamic_pointer_cast(t); } diff --git a/Record/main.h b/Record/main.h index 6289dec..6092fba 100644 --- a/Record/main.h +++ b/Record/main.h @@ -5,6 +5,8 @@ #include #include +class SpeexDsp; + class Task { public: virtual void run() = 0; @@ -21,6 +23,7 @@ private: class PlayerTask : public Task { public: + void setChannels(int channels); void setPath(const std::string &path); void run() final; @@ -28,7 +31,9 @@ protected: void play(); private: + int m_channels = 2; std::string m_path; + std::vector m_buffer; std::shared_ptr m_ifs; std::shared_ptr m_output; }; @@ -44,6 +49,8 @@ private: bool m_vqeEnabled = false; std::shared_ptr m_output; std::shared_ptr m_input; + std::shared_ptr m_speex; + std::vector m_buffer; }; #endif // __MAIN_H__ \ No newline at end of file