Tasmota/lib/libesp32/berry_tasmota/src/be_i2s_audio_lib.cpp
2022-01-30 11:07:15 +01:00

251 lines
8.2 KiB
C++

/********************************************************************
* Tasmota I2S audio classes
*
*
*******************************************************************/
#include "be_constobj.h"
#ifdef USE_I2S
#ifdef USE_I2S_AUDIO_BERRY
#include "be_mapping.h"
#include "AudioOutput.h"
extern "C" void berry_log_C(const char * berry_buf, ...);
extern "C" {
extern int i2s_output_i2s_init(bvm *vm);
extern int i2s_output_i2s_deinit(bvm *vm);
extern int i2s_output_i2s_stop(bvm *vm);
extern int i2s_generator_wav_init(bvm *vm);
extern int i2s_generator_wav_deinit(bvm *vm);
extern int i2s_generator_wav_begin(bvm *vm);
extern int i2s_generator_wav_loop(bvm *vm);
extern int i2s_generator_wav_stop(bvm *vm);
extern int i2s_generator_wav_isrunning(bvm *vm);
extern int i2s_generator_mp3_init(bvm *vm);
extern int i2s_generator_mp3_deinit(bvm *vm);
extern int i2s_generator_mp3_begin(bvm *vm);
extern int i2s_generator_mp3_loop(bvm *vm);
extern int i2s_generator_mp3_stop(bvm *vm);
extern int i2s_generator_mp3_isrunning(bvm *vm);
#ifdef USE_UFILESYS
extern int i2s_file_source_fs_init(bvm *vm);
extern int i2s_file_source_fs_deinit(bvm *vm);
#endif // USE_UFILESYS
}
// AudioOutput.set_rate(rate_hz:int) -> bool
AudioOutput* be_audio_output_init_ntv(void) {
return new AudioOutput();
}
int32_t be_audio_output_init(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_init_ntv, "+.p", "");
}
// AudioOutput.set_rate(rate_hz:int) -> bool
int be_audio_output_set_rate_ntv(AudioOutput* out, int hz) {
return out->SetRate(hz);
}
int32_t be_audio_output_set_rate(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_set_rate_ntv, "b", ".i");
}
// AudioOutput.set_bits_per_sample(bits_per_sample:int) -> bool
int be_audio_output_set_bits_per_sample_ntv(AudioOutput* out, int bps) {
return out->SetBitsPerSample(bps);
}
int32_t be_audio_output_set_bits_per_sample(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_set_bits_per_sample_ntv, "b", ".i");
}
// AudioOutput.set_channels(channels:int) -> bool
int be_audio_output_set_channels_ntv(AudioOutput* out, int channels) {
return out->SetChannels(channels);
}
int32_t be_audio_output_set_channels(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_set_channels_ntv, "b", ".i");
}
// AudioOutput.set_gain(gain:real) -> bool
int be_audio_output_set_gain_ntv(AudioOutput* out, float gain) {
return out->SetGain(gain);
}
int32_t be_audio_output_set_gain(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_set_gain_ntv, "b", ".f");
}
// AudioOutput.begin() -> bool
int be_audio_output_begin_ntv(AudioOutput* out) {
return out->begin();
}
int32_t be_audio_output_begin(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_begin_ntv, "b", ".");
}
// AudioOutput.stop() -> bool
int be_audio_output_stop_ntv(AudioOutput* out) {
return out->stop();
}
int32_t be_audio_output_stop(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_stop_ntv, "b", ".");
}
// AudioOutput.flush() -> bool
void be_audio_output_flush_ntv(AudioOutput* out) {
out->flush();
}
int32_t be_audio_output_flush(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_flush_ntv, "", ".");
}
// AudioOutput.consume_mono(bytes) -> int
int be_audio_output_consume_mono_ntv(AudioOutput* out, uint16_t *pcm, int bytes_len, int index) {
int pcm_len = bytes_len / 2;
int n;
// berry_log_C("be_audio_output_consume_mono_ntv out=%p pcm=%p bytes_len=%i index=%i", out, pcm, bytes_len, index);
for (n = 0; index + n < pcm_len; n++) {
int16_t ms[2];
ms[AudioOutput::LEFTCHANNEL] = ms[AudioOutput::RIGHTCHANNEL] = pcm[index + n];
if (!out->ConsumeSample(ms)) { break; }
}
return n;
}
int32_t be_audio_output_consume_mono(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_consume_mono_ntv, "i", ".(bytes)~i");
}
// AudioOutput.consume_stereo(bytes) -> int
int be_audio_output_consume_stereo_ntv(AudioOutput* out, uint16_t *pcm, int bytes_len, int index) {
int pcm_len = bytes_len / 4; // 2 samples LEFT+RIGHT of 2 bytes each
int n;
// berry_log_C("be_audio_output_consume_stereo_ntv out=%p pcm=%p bytes_len=%i index=%i", out, pcm, bytes_len, index);
for (n = 0; index + n < pcm_len; n++) {
int16_t ms[2];
ms[AudioOutput::LEFTCHANNEL] = pcm[index + n + n];
ms[AudioOutput::RIGHTCHANNEL] = pcm[index + n + n + 1];
if (!out->ConsumeSample(ms)) { break; }
}
return n;
}
int32_t be_audio_output_consume_stereo(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_consume_stereo_ntv, "i", ".(bytes)~i");
}
// AudioOutput.consume_silence() -> int, push silence frames
int be_audio_output_consume_silence_ntv(AudioOutput* out) {
int n = 0;
int16_t ms[2] = {0, 0};
while (true) {
if (!out->ConsumeSample(ms)) { break; }
n++;
}
return n;
}
int32_t be_audio_output_consume_silence(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_audio_output_consume_silence_ntv, "i", ".");
}
#include "AudioOutputI2S.h"
extern "C" {
#include "be_fixed_be_class_audio_output.h"
#include "be_fixed_be_class_audio_output_i2s.h"
#include "be_fixed_be_class_audio_generator.h"
#include "be_fixed_be_class_audio_generator_wav.h"
#include "be_fixed_be_class_audio_generator_mp3.h"
#include "be_fixed_be_class_audio_file_source.h"
#include "be_fixed_be_class_audio_file_source_fs.h"
void be_load_driver_audio_lib(bvm *vm) {
be_pushntvclass(vm, &be_class_audio_output);
be_setglobal(vm, "AudioOutput");
be_pop(vm, 1);
be_pushntvclass(vm, &be_class_audio_output_i2s);
be_setglobal(vm, "AudioOutputI2S");
be_pop(vm, 1);
be_pushntvclass(vm, &be_class_audio_generator_wav);
be_setglobal(vm, "AudioGeneratorWAV");
be_pop(vm, 1);
be_pushntvclass(vm, &be_class_audio_generator_mp3);
be_setglobal(vm, "AudioGeneratorMP3");
be_pop(vm, 1);
#ifdef USE_UFILESYS
be_pushntvclass(vm, &be_class_audio_file_source_fs);
be_setglobal(vm, "AudioFileSourceFS");
be_pop(vm, 1);
#endif // USE_UFILESYS
}
}
/* @const_object_info_begin
class be_class_audio_output (scope: global, name: AudioOutput) {
.p, var
init, func(be_audio_output_init)
begin, func(be_audio_output_begin)
stop, func(be_audio_output_stop)
flush, func(be_audio_output_flush)
consume_mono, func(be_audio_output_consume_mono)
consume_stereo, func(be_audio_output_consume_stereo)
consume_silence, func(be_audio_output_consume_silence)
set_rate, func(be_audio_output_set_rate)
set_bits_per_sample, func(be_audio_output_set_bits_per_sample)
set_channels, func(be_audio_output_set_channels)
set_gain, func(be_audio_output_set_gain)
}
class be_class_audio_generator (scope: global, name: AudioGenerator) {
.p, var
}
class be_class_audio_file_source (scope: global, name: AudioFileSource) {
.p, var
}
class be_class_audio_output_i2s (scope: global, name: AudioOutputI2S, super: be_class_audio_output) {
EXTERNAL_I2S, int(AudioOutputI2S::EXTERNAL_I2S)
INTERNAL_DAC, int(AudioOutputI2S::INTERNAL_DAC)
INTERNAL_PDM, int(AudioOutputI2S::INTERNAL_PDM)
init, func(i2s_output_i2s_init)
deinit, func(i2s_output_i2s_deinit)
stop, func(i2s_output_i2s_stop)
}
class be_class_audio_generator_wav (scope: global, name: AudioGeneratorWAV, super: be_class_audio_generator) {
init, func(i2s_generator_wav_init)
deinit, func(i2s_generator_wav_deinit)
begin, func(i2s_generator_wav_begin)
loop, func(i2s_generator_wav_loop)
stop, func(i2s_generator_wav_stop)
isrunning, func(i2s_generator_wav_isrunning)
}
class be_class_audio_generator_mp3 (scope: global, name: AudioGeneratorMP3, super: be_class_audio_generator) {
init, func(i2s_generator_mp3_init)
deinit, func(i2s_generator_mp3_deinit)
begin, func(i2s_generator_mp3_begin)
loop, func(i2s_generator_mp3_loop)
stop, func(i2s_generator_mp3_stop)
isrunning, func(i2s_generator_mp3_isrunning)
}
class be_class_audio_file_source_fs (scope: global, name: AudioFileSourceFS, super: be_class_audio_file_source) {
init, func(i2s_file_source_fs_init)
deinit, func(i2s_file_source_fs_deinit)
}
@const_object_info_end */
#endif // USE_I2S_AUDIO_BERRY
#endif // USE_I2S