Skip to content

Commit

Permalink
Update WAV Player, 16 bit support
Browse files Browse the repository at this point in the history
by @LTVA1, in current condition has some issues with rewind on 16bit files, but plays them without problems
  • Loading branch information
xMasterX committed Mar 18, 2023
1 parent 56c11c7 commit 76d3f84
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 9 deletions.
4 changes: 2 additions & 2 deletions applications/external/wav_player/README.md
@@ -1,4 +1,4 @@
# WAV player
A Flipper Zero application for playing wav files. My fork adds support for correct playback speed (for files with different sample rates) and for mono files (original wav player only plays stereo). You still need to convert your file to unsigned 8-bit PCM format for it to played correctly on flipper.
A Flipper Zero application for playing wav files. My fork adds support for correct playback speed (for files with different sample rates) and for mono files (original wav player only plays stereo). ~~You still need to convert your file to unsigned 8-bit PCM format for it to played correctly on flipper~~. Now supports 16-bit (ordinary) wav files too, both mono and stereo!

Original app by https://github.com/DrZlo13.
Original app by https://github.com/DrZlo13.
111 changes: 109 additions & 2 deletions applications/external/wav_player/wav_player.c
Expand Up @@ -127,7 +127,7 @@ static void app_free(WavPlayerApp* app) {

// TODO: that works only with 8-bit 2ch audio
static bool fill_data(WavPlayerApp* app, size_t index) {
if(app->num_channels == 1) {
if(app->num_channels == 1 && app->bits_per_sample == 8) {
uint16_t* sample_buffer_start = &app->sample_buffer[index];
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count_half);

Expand Down Expand Up @@ -166,7 +166,108 @@ static bool fill_data(WavPlayerApp* app, size_t index) {
return count != app->samples_count_half;
}

if(app->num_channels == 2) {
if(app->num_channels == 1 && app->bits_per_sample == 16) {
uint16_t* sample_buffer_start = &app->sample_buffer[index];
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);

for(size_t i = count; i < app->samples_count; i++) {
//app->tmp_buffer[i] = 0;
}

for(size_t i = 0; i < app->samples_count; i += 2) {
int16_t int_16 =
(((int16_t)app->tmp_buffer[i + 1] << 8) + (int16_t)app->tmp_buffer[i]);

float data = ((float)int_16 / 256.0 + 127.0);
data -= UINT8_MAX / 2; // to signed
data /= UINT8_MAX / 2; // scale -1..1

data *= app->volume; // volume
data = tanhf(data); // hyperbolic tangent limiter

data *= UINT8_MAX / 2; // scale -128..127
data += UINT8_MAX / 2; // to unsigned

if(data < 0) {
data = 0;
}

if(data > 255) {
data = 255;
}

sample_buffer_start[i / 2] = data;
}

wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);

return count != app->samples_count;
}

if(app->num_channels == 2 && app->bits_per_sample == 16) {
uint16_t* sample_buffer_start = &app->sample_buffer[index];
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);

for(size_t i = 0; i < app->samples_count; i += 4) {
int16_t L = (((int16_t)app->tmp_buffer[i + 1] << 8) + (int16_t)app->tmp_buffer[i]);
int16_t R = (((int16_t)app->tmp_buffer[i + 3] << 8) + (int16_t)app->tmp_buffer[i + 2]);
int32_t int_16 = L / 2 + R / 2; // (L + R) / 2

float data = ((float)int_16 / 256.0 + 127.0);
data -= UINT8_MAX / 2; // to signed
data /= UINT8_MAX / 2; // scale -1..1

data *= app->volume; // volume
data = tanhf(data); // hyperbolic tangent limiter

data *= UINT8_MAX / 2; // scale -128..127
data += UINT8_MAX / 2; // to unsigned

if(data < 0) {
data = 0;
}

if(data > 255) {
data = 255;
}

sample_buffer_start[i / 4] = data;
}

count = stream_read(app->stream, app->tmp_buffer, app->samples_count);

for(size_t i = 0; i < app->samples_count; i += 4) {
int16_t L = (((int16_t)app->tmp_buffer[i + 1] << 8) + (int16_t)app->tmp_buffer[i]);
int16_t R = (((int16_t)app->tmp_buffer[i + 3] << 8) + (int16_t)app->tmp_buffer[i + 2]);
int32_t int_16 = L / 2 + R / 2; // (L + R) / 2

float data = ((float)int_16 / 256.0 + 127.0);
data -= UINT8_MAX / 2; // to signed
data /= UINT8_MAX / 2; // scale -1..1

data *= app->volume; // volume
data = tanhf(data); // hyperbolic tangent limiter

data *= UINT8_MAX / 2; // scale -128..127
data += UINT8_MAX / 2; // to unsigned

if(data < 0) {
data = 0;
}

if(data > 255) {
data = 255;
}

sample_buffer_start[i / 4 + app->samples_count / 4] = data;
}

wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);

return count != app->samples_count;
}

if(app->num_channels == 2 && app->bits_per_sample == 8) {
uint16_t* sample_buffer_start = &app->sample_buffer[index];
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);

Expand Down Expand Up @@ -270,6 +371,9 @@ static void app_run(WavPlayerApp* app) {
while(1) {
if(furi_message_queue_get(app->queue, &event, FuriWaitForever) == FuriStatusOk) {
if(event.type == WavPlayerEventHalfTransfer) {
wav_player_view_set_chans(app->view, app->num_channels);
wav_player_view_set_bits(app->view, app->bits_per_sample);

eof = fill_data(app, 0);
wav_player_view_set_current(app->view, stream_tell(app->stream));
if(eof) {
Expand All @@ -280,6 +384,9 @@ static void app_run(WavPlayerApp* app) {
}

} else if(event.type == WavPlayerEventFullTransfer) {
wav_player_view_set_chans(app->view, app->num_channels);
wav_player_view_set_bits(app->view, app->bits_per_sample);

eof = fill_data(app, app->samples_count_half);
wav_player_view_set_current(app->view, stream_tell(app->stream));
if(eof) {
Expand Down
6 changes: 1 addition & 5 deletions applications/external/wav_player/wav_player_hal.c
Expand Up @@ -35,7 +35,7 @@ void wav_player_speaker_init(uint32_t sample_rate) {
TIM_InitStruct.Prescaler = 0;
//TIM_InitStruct.Autoreload = 1451; //64 000 000 / 1451 ~= 44100 Hz

TIM_InitStruct.Autoreload = 64000000 / sample_rate; //to support various sample rates
TIM_InitStruct.Autoreload = 64000000 / sample_rate - 1; //to support various sample rates

LL_TIM_Init(SAMPLE_RATE_TIMER, &TIM_InitStruct);

Expand All @@ -48,16 +48,12 @@ void wav_player_speaker_init(uint32_t sample_rate) {
//=========================================================
//configuring PA6 pin as TIM16 output

//furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedVeryHigh, GpioAltFn14TIM16);
//furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedLow, GpioAltFn14TIM16);
furi_hal_gpio_init_ex(
&gpio_ext_pa6,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn14TIM16);
//furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull);
//furi_hal_gpio_write(&gpio_ext_pa6, false);
}

void wav_player_speaker_start() {
Expand Down
18 changes: 18 additions & 0 deletions applications/external/wav_player/wav_player_view.c
Expand Up @@ -12,6 +12,12 @@ static void wav_player_view_draw_callback(Canvas* canvas, void* _model) {
uint8_t x_pos = 0;
uint8_t y_pos = 0;

/*char buffer[20];
snprintf(buffer, sizeof(buffer), "%d", model->num_channels);
canvas_draw_str(canvas, 0, 10, buffer);
snprintf(buffer, sizeof(buffer), "%d", model->bits_per_sample);
canvas_draw_str(canvas, 0, 20, buffer);*/

// volume
x_pos = 123;
y_pos = 0;
Expand Down Expand Up @@ -156,6 +162,18 @@ void wav_player_view_set_play(WavPlayerView* wav_view, bool play) {
wav_view->view, WavPlayerViewModel * model, { model->play = play; }, true);
}

void wav_player_view_set_chans(WavPlayerView* wav_view, uint16_t chn) {
furi_assert(wav_view);
with_view_model(
wav_view->view, WavPlayerViewModel * model, { model->num_channels = chn; }, true);
}

void wav_player_view_set_bits(WavPlayerView* wav_view, uint16_t bit) {
furi_assert(wav_view);
with_view_model(
wav_view->view, WavPlayerViewModel * model, { model->bits_per_sample = bit; }, true);
}

void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count) {
furi_assert(wav_view);
with_view_model(
Expand Down
6 changes: 6 additions & 0 deletions applications/external/wav_player/wav_player_view.h
Expand Up @@ -43,6 +43,9 @@ typedef struct {
size_t end;
size_t current;
uint8_t data[DATA_COUNT];

uint16_t bits_per_sample;
uint16_t num_channels;
} WavPlayerViewModel;

WavPlayerView* wav_player_view_alloc();
Expand All @@ -63,6 +66,9 @@ void wav_player_view_set_play(WavPlayerView* wav_view, bool play);

void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count);

void wav_player_view_set_bits(WavPlayerView* wav_view, uint16_t bit);
void wav_player_view_set_chans(WavPlayerView* wav_view, uint16_t chn);

void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback);

void wav_player_view_set_context(WavPlayerView* wav_view, void* context);
Expand Down

0 comments on commit 76d3f84

Please sign in to comment.