124 lines
4.5 KiB
C++
124 lines
4.5 KiB
C++
#include "simple_pipeline.h"
|
|
#include "boards/common/board.h"
|
|
#include "audio_codecs/audio_codec.h"
|
|
#include <vector>
|
|
#include <cstring>
|
|
|
|
static inline int16_t lrint16(float v){ if(v>32767.f) return 32767; if(v<-32768.f) return -32768; return (int16_t)v; }
|
|
|
|
static void resample_mono_nearest(const int16_t* in, int in_samples, int in_rate, int16_t* out, int out_samples, int out_rate){
|
|
if(in_rate==out_rate){ for(int i=0;i<out_samples;i++) out[i]=in[i]; return; }
|
|
float ratio = (float)in_rate/(float)out_rate;
|
|
for(int i=0;i<out_samples;i++){ int idx = (int)(i*ratio); if(idx>=in_samples) idx=in_samples-1; out[i]=in[idx]; }
|
|
}
|
|
|
|
recorder_pipeline_handle_t recorder_pipeline_open(){
|
|
auto h = (recorder_pipeline_handle_t)pvPortMalloc(sizeof(recorder_pipeline_t));
|
|
h->task = nullptr;
|
|
h->dest_rate = 16000;
|
|
auto codec = Board::GetInstance().GetAudioCodec();
|
|
h->src_rate = codec->input_sample_rate();
|
|
h->channels = 1;
|
|
h->block_bytes = (h->dest_rate/50)*sizeof(int16_t);
|
|
codec->EnableInput(true);
|
|
return h;
|
|
}
|
|
|
|
void recorder_pipeline_run(recorder_pipeline_handle_t){ }
|
|
|
|
void recorder_pipeline_close(recorder_pipeline_handle_t h){
|
|
if(!h) return;
|
|
if (h->task) {
|
|
vTaskDelete(h->task);
|
|
}
|
|
auto codec = Board::GetInstance().GetAudioCodec();
|
|
codec->EnableInput(false);
|
|
vPortFree(h);
|
|
}
|
|
|
|
int recorder_pipeline_get_default_read_size(recorder_pipeline_handle_t h){ return h? h->block_bytes: 0; }
|
|
|
|
int recorder_pipeline_read(recorder_pipeline_handle_t h, char *buffer, int buf_size){
|
|
if(!h || !buffer) return 0;
|
|
auto codec = Board::GetInstance().GetAudioCodec();
|
|
int out_samples = h->dest_rate/50;
|
|
std::vector<int16_t> tmp;
|
|
if(h->src_rate==h->dest_rate){ tmp.resize(out_samples); }
|
|
else{ tmp.resize((int)((float)out_samples*h->src_rate/h->dest_rate)); }
|
|
if(!codec->InputData(tmp)) return 0;
|
|
std::vector<int16_t> out(out_samples);
|
|
resample_mono_nearest(tmp.data(), (int)tmp.size(), h->src_rate, out.data(), out_samples, h->dest_rate);
|
|
int bytes = out_samples*sizeof(int16_t);
|
|
if(bytes>buf_size) bytes=buf_size;
|
|
memcpy(buffer, out.data(), bytes);
|
|
return bytes;
|
|
}
|
|
|
|
player_pipeline_handle_t player_pipeline_open(){
|
|
auto h = (player_pipeline_handle_t)pvPortMalloc(sizeof(player_pipeline_t));
|
|
h->task = nullptr;
|
|
h->src_rate = 16000;
|
|
auto codec = Board::GetInstance().GetAudioCodec();
|
|
h->dest_rate = codec->output_sample_rate();
|
|
h->channels = codec->output_channels();
|
|
h->block_bytes = (h->src_rate/50)*sizeof(int16_t);
|
|
h->fade_total = h->dest_rate / 10; // 100ms淡入
|
|
h->fade_done = 0;
|
|
codec->EnableOutput(true);
|
|
return h;
|
|
}
|
|
|
|
void player_pipeline_run(player_pipeline_handle_t){ }
|
|
|
|
void player_pipeline_close(player_pipeline_handle_t h){
|
|
if(!h) return;
|
|
if (h->task) {
|
|
vTaskDelete(h->task);
|
|
}
|
|
auto codec = Board::GetInstance().GetAudioCodec();
|
|
codec->EnableOutput(false);
|
|
vPortFree(h);
|
|
}
|
|
|
|
int player_pipeline_get_default_read_size(player_pipeline_handle_t h){ return h? h->block_bytes: 0; }
|
|
|
|
int player_pipeline_write(player_pipeline_handle_t h, char *buffer, int buf_size){
|
|
if(!h || !buffer || buf_size<=0) return 0;
|
|
int in_samples = buf_size/sizeof(int16_t);
|
|
std::vector<int16_t> in(in_samples);
|
|
memcpy(in.data(), buffer, buf_size);
|
|
int out_samples = (int)((float)in_samples*h->dest_rate/h->src_rate);
|
|
std::vector<int16_t> out(out_samples);
|
|
resample_mono_nearest(in.data(), in_samples, h->src_rate, out.data(), out_samples, h->dest_rate);
|
|
if (h->fade_done < h->fade_total) {
|
|
int n = out_samples;
|
|
for (int i = 0; i < n; ++i) {
|
|
int done = h->fade_done + i;
|
|
float g = done < h->fade_total ? (float)done / (float)h->fade_total : 1.0f;
|
|
out[i] = lrint16((float)out[i] * g);
|
|
}
|
|
h->fade_done += n;
|
|
if (h->fade_done > h->fade_total) h->fade_done = h->fade_total;
|
|
}
|
|
auto codec = Board::GetInstance().GetAudioCodec();
|
|
if (h->channels == 2) {
|
|
std::vector<int16_t> stereo(out_samples * 2);
|
|
for (int i = 0, j = 0; i < out_samples; ++i) {
|
|
stereo[j++] = out[i];
|
|
stereo[j++] = out[i];
|
|
}
|
|
codec->OutputData(stereo);
|
|
} else {
|
|
codec->OutputData(out);
|
|
}
|
|
return buf_size;
|
|
}
|
|
|
|
void player_pipeline_write_play_buffer_flag(player_pipeline_handle_t){ }
|
|
|
|
void player_pipeline_set_src_rate(player_pipeline_handle_t h, int rate){
|
|
if (!h || rate <= 0) return;
|
|
h->src_rate = rate;
|
|
h->block_bytes = (h->src_rate/50)*sizeof(int16_t);
|
|
}
|