Просмотр исходного кода

16-bit WAV support, I hope, both mono and stereo

LTVA1 2 лет назад
Родитель
Сommit
52ed499d37
4 измененных файлов с 138 добавлено и 3 удалено
  1. 1 1
      application.fam
  2. 113 2
      wav_player.c
  3. 18 0
      wav_player_view.c
  4. 6 0
      wav_player_view.h

+ 1 - 1
application.fam

@@ -7,6 +7,6 @@ App(
     stack_size=4 * 1024,
     order=60,
     fap_icon="wav_10px.png",
-    fap_category="Music",
+    fap_category="Media",
     fap_icon_assets="images",
 )

+ 113 - 2
wav_player.c

@@ -129,7 +129,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);
@@ -169,7 +169,112 @@ 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);
@@ -275,6 +380,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) {
@@ -285,6 +393,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) {

+ 18 - 0
wav_player_view.c

@@ -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;
@@ -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(

+ 6 - 0
wav_player_view.h

@@ -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;
 
 
@@ -67,6 +70,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);