Skip to content

Commit 76d3f84

Browse files
committed
Update WAV Player, 16 bit support
by @LTVA1, in current condition has some issues with rewind on 16bit files, but plays them without problems
1 parent 56c11c7 commit 76d3f84

File tree

5 files changed

+136
-9
lines changed

5 files changed

+136
-9
lines changed
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# WAV player
2-
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.
2+
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!
33

4-
Original app by https://github.com/DrZlo13.
4+
Original app by https://github.com/DrZlo13.

applications/external/wav_player/wav_player.c

+109-2
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ static void app_free(WavPlayerApp* app) {
127127

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

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

169-
if(app->num_channels == 2) {
169+
if(app->num_channels == 1 && app->bits_per_sample == 16) {
170+
uint16_t* sample_buffer_start = &app->sample_buffer[index];
171+
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
172+
173+
for(size_t i = count; i < app->samples_count; i++) {
174+
//app->tmp_buffer[i] = 0;
175+
}
176+
177+
for(size_t i = 0; i < app->samples_count; i += 2) {
178+
int16_t int_16 =
179+
(((int16_t)app->tmp_buffer[i + 1] << 8) + (int16_t)app->tmp_buffer[i]);
180+
181+
float data = ((float)int_16 / 256.0 + 127.0);
182+
data -= UINT8_MAX / 2; // to signed
183+
data /= UINT8_MAX / 2; // scale -1..1
184+
185+
data *= app->volume; // volume
186+
data = tanhf(data); // hyperbolic tangent limiter
187+
188+
data *= UINT8_MAX / 2; // scale -128..127
189+
data += UINT8_MAX / 2; // to unsigned
190+
191+
if(data < 0) {
192+
data = 0;
193+
}
194+
195+
if(data > 255) {
196+
data = 255;
197+
}
198+
199+
sample_buffer_start[i / 2] = data;
200+
}
201+
202+
wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);
203+
204+
return count != app->samples_count;
205+
}
206+
207+
if(app->num_channels == 2 && app->bits_per_sample == 16) {
208+
uint16_t* sample_buffer_start = &app->sample_buffer[index];
209+
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
210+
211+
for(size_t i = 0; i < app->samples_count; i += 4) {
212+
int16_t L = (((int16_t)app->tmp_buffer[i + 1] << 8) + (int16_t)app->tmp_buffer[i]);
213+
int16_t R = (((int16_t)app->tmp_buffer[i + 3] << 8) + (int16_t)app->tmp_buffer[i + 2]);
214+
int32_t int_16 = L / 2 + R / 2; // (L + R) / 2
215+
216+
float data = ((float)int_16 / 256.0 + 127.0);
217+
data -= UINT8_MAX / 2; // to signed
218+
data /= UINT8_MAX / 2; // scale -1..1
219+
220+
data *= app->volume; // volume
221+
data = tanhf(data); // hyperbolic tangent limiter
222+
223+
data *= UINT8_MAX / 2; // scale -128..127
224+
data += UINT8_MAX / 2; // to unsigned
225+
226+
if(data < 0) {
227+
data = 0;
228+
}
229+
230+
if(data > 255) {
231+
data = 255;
232+
}
233+
234+
sample_buffer_start[i / 4] = data;
235+
}
236+
237+
count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
238+
239+
for(size_t i = 0; i < app->samples_count; i += 4) {
240+
int16_t L = (((int16_t)app->tmp_buffer[i + 1] << 8) + (int16_t)app->tmp_buffer[i]);
241+
int16_t R = (((int16_t)app->tmp_buffer[i + 3] << 8) + (int16_t)app->tmp_buffer[i + 2]);
242+
int32_t int_16 = L / 2 + R / 2; // (L + R) / 2
243+
244+
float data = ((float)int_16 / 256.0 + 127.0);
245+
data -= UINT8_MAX / 2; // to signed
246+
data /= UINT8_MAX / 2; // scale -1..1
247+
248+
data *= app->volume; // volume
249+
data = tanhf(data); // hyperbolic tangent limiter
250+
251+
data *= UINT8_MAX / 2; // scale -128..127
252+
data += UINT8_MAX / 2; // to unsigned
253+
254+
if(data < 0) {
255+
data = 0;
256+
}
257+
258+
if(data > 255) {
259+
data = 255;
260+
}
261+
262+
sample_buffer_start[i / 4 + app->samples_count / 4] = data;
263+
}
264+
265+
wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);
266+
267+
return count != app->samples_count;
268+
}
269+
270+
if(app->num_channels == 2 && app->bits_per_sample == 8) {
170271
uint16_t* sample_buffer_start = &app->sample_buffer[index];
171272
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
172273

@@ -270,6 +371,9 @@ static void app_run(WavPlayerApp* app) {
270371
while(1) {
271372
if(furi_message_queue_get(app->queue, &event, FuriWaitForever) == FuriStatusOk) {
272373
if(event.type == WavPlayerEventHalfTransfer) {
374+
wav_player_view_set_chans(app->view, app->num_channels);
375+
wav_player_view_set_bits(app->view, app->bits_per_sample);
376+
273377
eof = fill_data(app, 0);
274378
wav_player_view_set_current(app->view, stream_tell(app->stream));
275379
if(eof) {
@@ -280,6 +384,9 @@ static void app_run(WavPlayerApp* app) {
280384
}
281385

282386
} else if(event.type == WavPlayerEventFullTransfer) {
387+
wav_player_view_set_chans(app->view, app->num_channels);
388+
wav_player_view_set_bits(app->view, app->bits_per_sample);
389+
283390
eof = fill_data(app, app->samples_count_half);
284391
wav_player_view_set_current(app->view, stream_tell(app->stream));
285392
if(eof) {

applications/external/wav_player/wav_player_hal.c

+1-5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void wav_player_speaker_init(uint32_t sample_rate) {
3535
TIM_InitStruct.Prescaler = 0;
3636
//TIM_InitStruct.Autoreload = 1451; //64 000 000 / 1451 ~= 44100 Hz
3737

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

4040
LL_TIM_Init(SAMPLE_RATE_TIMER, &TIM_InitStruct);
4141

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

51-
//furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedVeryHigh, GpioAltFn14TIM16);
52-
//furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedLow, GpioAltFn14TIM16);
5351
furi_hal_gpio_init_ex(
5452
&gpio_ext_pa6,
5553
GpioModeAltFunctionPushPull,
5654
GpioPullNo,
5755
GpioSpeedVeryHigh,
5856
GpioAltFn14TIM16);
59-
//furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull);
60-
//furi_hal_gpio_write(&gpio_ext_pa6, false);
6157
}
6258

6359
void wav_player_speaker_start() {

applications/external/wav_player/wav_player_view.c

+18
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ static void wav_player_view_draw_callback(Canvas* canvas, void* _model) {
1212
uint8_t x_pos = 0;
1313
uint8_t y_pos = 0;
1414

15+
/*char buffer[20];
16+
snprintf(buffer, sizeof(buffer), "%d", model->num_channels);
17+
canvas_draw_str(canvas, 0, 10, buffer);
18+
snprintf(buffer, sizeof(buffer), "%d", model->bits_per_sample);
19+
canvas_draw_str(canvas, 0, 20, buffer);*/
20+
1521
// volume
1622
x_pos = 123;
1723
y_pos = 0;
@@ -156,6 +162,18 @@ void wav_player_view_set_play(WavPlayerView* wav_view, bool play) {
156162
wav_view->view, WavPlayerViewModel * model, { model->play = play; }, true);
157163
}
158164

165+
void wav_player_view_set_chans(WavPlayerView* wav_view, uint16_t chn) {
166+
furi_assert(wav_view);
167+
with_view_model(
168+
wav_view->view, WavPlayerViewModel * model, { model->num_channels = chn; }, true);
169+
}
170+
171+
void wav_player_view_set_bits(WavPlayerView* wav_view, uint16_t bit) {
172+
furi_assert(wav_view);
173+
with_view_model(
174+
wav_view->view, WavPlayerViewModel * model, { model->bits_per_sample = bit; }, true);
175+
}
176+
159177
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count) {
160178
furi_assert(wav_view);
161179
with_view_model(

applications/external/wav_player/wav_player_view.h

+6
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ typedef struct {
4343
size_t end;
4444
size_t current;
4545
uint8_t data[DATA_COUNT];
46+
47+
uint16_t bits_per_sample;
48+
uint16_t num_channels;
4649
} WavPlayerViewModel;
4750

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

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

69+
void wav_player_view_set_bits(WavPlayerView* wav_view, uint16_t bit);
70+
void wav_player_view_set_chans(WavPlayerView* wav_view, uint16_t chn);
71+
6672
void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback);
6773

6874
void wav_player_view_set_context(WavPlayerView* wav_view, void* context);

0 commit comments

Comments
 (0)