shithub: mp3dec

Download patch

ref: 37a53d4658e02914020e2bd45c56c6afab7d2e56
parent: 82553bff3ef9e3750ec1f16b74e0d7c0b1b4d5fa
author: lieff <lieff@users.noreply.github.com>
date: Fri Apr 27 11:36:48 EDT 2018

sample player WIP

--- a/player/audio_sdl.c
+++ b/player/audio_sdl.c
@@ -5,11 +5,8 @@
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
-#include "decode.h"
+#include "audio_sdl.h"
 
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
 #define SDL2
 
 typedef struct audio_ctx
@@ -18,21 +15,13 @@
     int dev;
 #endif
     SDL_AudioSpec outputSpec;
+    decoder *dec;
 } audio_ctx;
 
-decoder _dec;
-
 static void audio_cb(void *udata, Uint8 *stream, int len)
 {
     audio_ctx *ctx = (audio_ctx *)udata;
-    memset(stream, 0, len);
-    EnterCriticalSection(&_dec.mp3_lock);
-    if ((_dec.mp3_size - _dec.mp3_pos) >= len)
-    {
-        memcpy(stream, (char*)_dec.mp3_buf + _dec.mp3_pos, len);
-        _dec.mp3_pos += len;
-    }
-    LeaveCriticalSection(&_dec.mp3_lock);
+    decode_samples(ctx->dec, stream, len);
 }
 
 int sdl_audio_init(void **audio_render, int samplerate, int channels, int format, int buffer)
@@ -68,11 +57,6 @@
         return 0;
     }
 #endif
-#ifdef SDL2
-    SDL_PauseAudioDevice(dev, 0);
-#else
-    SDL_PauseAudio(0);
-#endif
     *audio_render = ctx;
     return 1;
 }
@@ -91,4 +75,23 @@
     SDL_CloseAudio();
 #endif
     free(ctx);
+}
+
+void sdl_audio_set_dec(void *audio_render, decoder *dec)
+{
+    audio_ctx *ctx = (audio_ctx *)audio_render;
+#ifdef SDL2
+    SDL_PauseAudioDevice(ctx->dev, 1);
+#else
+    SDL_PauseAudio(1);
+#endif
+    ctx->dec = dec;
+    if (dec)
+    {
+#ifdef SDL2
+        SDL_PauseAudioDevice(ctx->dev, 0);
+#else
+        SDL_PauseAudio(0);
+#endif
+    }
 }
--- a/player/audio_sdl.h
+++ b/player/audio_sdl.h
@@ -1,4 +1,5 @@
 #pragma once
+#include "decode.h"
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -5,6 +6,7 @@
 
 int sdl_audio_init(void **audio_render, int samplerate, int channels, int format, int buffer);
 void sdl_audio_release(void *audio_render);
+void sdl_audio_set_dec(void *audio_render, decoder *dec);
 
 #ifdef __cplusplus
 }
--- a/player/decode.c
+++ b/player/decode.c
@@ -7,119 +7,125 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdlib.h>
+#include <math.h>
+#include "decode.h"
 #define MINIMP3_IMPLEMENTATION
 #include "../minimp3.h"
-#include "decode.h"
 
-static void add_audio(decoder *dec, short *buf, int bytes)
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static void get_spectrum(decoder *dec, int numch)
 {
-    char *buf_new = 0;
-    if (dec->mp3_allocated < (dec->mp3_size + bytes))
+    int i, ch, band;
+    const mp3dec_t *d = &dec->mp3d;
+    // Average spectrum power for 32 frequency band
+    for (ch = 0; ch < numch; ch++)
     {
-        int allocated = dec->mp3_allocated;
-        dec->mp3_allocated = dec->mp3_allocated ? dec->mp3_allocated*2 : 4*1024*1024;
-        buf_new = (char *)malloc(dec->mp3_allocated);
-        memcpy(buf_new, dec->mp3_buf, allocated);
+        for (band = 0; band < 32; band++)
+        {
+            float band_power = 0;
+            for (i = 0; i < 9; i++)
+            {
+                float sample = d->mdct_overlap[ch][i + band*9];
+                band_power += sample*sample;
+            }
+            // with averaging
+            //spectrum[band][ch] += (band_power/9 - spectrum[band][ch]) * 0.25;
+
+            // w/o averaging
+            dec->spectrum[band][ch] = band_power/9;
+        }
     }
-    EnterCriticalSection(&dec->mp3_lock);
-    if (buf_new)
+    // Calculate dB scale from power for better visualization
+    for (ch = 0; ch < numch; ch++)
     {
-        if (dec->mp3_buf)
-            free(dec->mp3_buf);
-        dec->mp3_buf = (short *)buf_new;
+        for (band = 0; band < 32; band++)
+        {
+            float power = dec->spectrum[band][ch];
+            float db_offset = 100;      // to shift dB values from [0..-inf] to [max..0]
+            float db = 10*log10(power + 1e-15) + db_offset;
+            if (db < 0) db = 0;
+            //printf("% .5f\t", db);
+        }
+        //printf("\n");
     }
-    memcpy((char*)dec->mp3_buf + dec->mp3_size, buf, bytes);
-    dec->mp3_size += bytes;
-    LeaveCriticalSection(&dec->mp3_lock);
 }
 
-static void *load_mp3_thread(void *lpThreadParameter)
+void decode_samples(decoder *dec, uint8_t *buf, int bytes)
 {
-    static mp3dec_t mp3d;
-    mp3dec_frame_info_t info = { 0, };
-    struct stat st;
-    decoder *dec = (decoder *)lpThreadParameter;
-    unsigned char *inputBuffer, *buf_mp3;
-    int file, mp3_size, samples;
-retry_open:
-    file = open(dec->file_name, O_RDONLY);
-    if (file < 0 && (errno == EAGAIN || errno == EINTR))
-        goto retry_open;
-    free((void*)dec->file_name);
-    dec->file_name = 0;
-    if (file < 0 || fstat(file, &st) < 0)
-        return (void*)(size_t)errno;
-
-    dec->mp3_file_size = st.st_size;
-retry_mmap:
-    inputBuffer = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, file, 0);
-    if (MAP_FAILED == inputBuffer && (errno == EAGAIN || errno == EINTR))
-        goto retry_mmap;
-    if (MAP_FAILED == inputBuffer)
+    int samples;
+    if (dec->pcm_bytes - dec->pcm_copied)
     {
-        close(file);
-        return (void*)(size_t)errno;
+        int to_copy = MIN(dec->pcm_bytes - dec->pcm_copied, bytes);
+        memcpy(buf, (uint8_t*)dec->pcm + dec->pcm_copied, to_copy);
+        buf   += to_copy;
+        bytes -= to_copy;
     }
-    buf_mp3 = inputBuffer;
-    mp3_size = dec->mp3_file_size;
-    mp3dec_init(&mp3d);
+    if (!bytes)
+        return;
     do
     {
-        short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
-        samples = mp3dec_decode_frame(&mp3d, buf_mp3, mp3_size, pcm, &info);
+        samples = mp3dec_decode_frame(&dec->mp3d, dec->mp3_buf + dec->pos, dec->mp3_size - dec->pos, dec->pcm, &dec->info);
+        dec->pos += dec->info.frame_bytes;
         if (samples)
         {
-            add_audio(dec, pcm, samples*2*info.channels);
+            get_spectrum(dec, dec->info.channels);
+            dec->pcm_bytes = samples*2*dec->info.channels;
+            dec->pcm_copied = MIN(dec->pcm_bytes, bytes);
+            memcpy(buf, dec->pcm, dec->pcm_copied);
+            buf   += dec->pcm_copied;
+            bytes -= dec->pcm_copied;
             if (!dec->mp3_rate)
-                dec->mp3_rate = info.hz;
+                dec->mp3_rate = dec->info.hz;
             if (!dec->mp3_channels)
-                dec->mp3_channels = info.channels;
-            if (dec->mp3_rate != info.hz || dec->mp3_channels != info.channels)
+                dec->mp3_channels = dec->info.channels;
+            if (dec->mp3_rate != dec->info.hz || dec->mp3_channels != dec->info.channels)
                 break;
         }
-        buf_mp3  += info.frame_bytes;
-        mp3_size -= info.frame_bytes;
-    } while (info.frame_bytes);
-
-    munmap(inputBuffer, st.st_size);
-    close(file);
-    return 0;
+    } while (dec->info.frame_bytes && bytes);
+    if (bytes)
+        memset(buf, 0, bytes);
 }
 
-int preload_mp3(decoder *dec, const char *file_name)
+int open_dec(decoder *dec, const char *file_name)
 {
-    if (dec->mp3_open_thread)
-    {
-        thread_wait(dec->mp3_open_thread);
-        thread_close(dec->mp3_open_thread);
-        dec->mp3_open_thread = 0;
-    }
-    EnterCriticalSection(&dec->mp3_lock);
-    if (dec->mp3_buf)
-    {
-        free(dec->mp3_buf);
-        dec->mp3_buf = 0;
-        dec->mp3_size = 0;
-        dec->mp3_pos = 0;
-        dec->mp3_allocated = 0;
-        dec->mp3_rate = 0;
-        dec->mp3_channels = 0;
-        dec->mp3_duration = 0;
-    }
-    LeaveCriticalSection(&dec->mp3_lock);
-
-    if (!file_name || !*file_name)
+    if (!dec || !file_name || !*file_name)
         return 0;
 
-    dec->file_name = strdup(file_name);
-    if (!dec->file_name)
+    memset(dec, 0, sizeof(*dec));
+
+    struct stat st;
+retry_open:
+    dec->file = open(file_name, O_RDONLY);
+    if (dec->file < 0 && (errno == EAGAIN || errno == EINTR))
+        goto retry_open;
+    if (dec->file < 0 || fstat(dec->file, &st) < 0)
+    {
+        close_dec(dec);
         return 0;
-    dec->mp3_open_thread = thread_create(load_mp3_thread, dec);
-    if (!dec->mp3_open_thread)
+    }
+
+    dec->mp3_size = st.st_size;
+retry_mmap:
+    dec->mp3_buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, dec->file, 0);
+    if (MAP_FAILED == dec->mp3_buf && (errno == EAGAIN || errno == EINTR))
+        goto retry_mmap;
+    if (MAP_FAILED == dec->mp3_buf)
     {
-        free((void*)dec->file_name);
-        dec->file_name = 0;
+        close_dec(dec);
         return 0;
     }
+    mp3dec_init(&dec->mp3d);
     return 1;
+}
+
+int close_dec(decoder *dec)
+{
+    if (dec->mp3_buf)
+        free(dec->mp3_buf);
+    if (dec->mp3_buf && MAP_FAILED != dec->mp3_buf)
+        munmap(dec->mp3_buf, dec->mp3_size);
+    if (dec->file)
+        close(dec->file);
+    memset(dec, 0, sizeof(*dec));
 }
--- a/player/decode.h
+++ b/player/decode.h
@@ -1,22 +1,31 @@
 #pragma once
-#include "system.h"
+#include <stdint.h>
+#include "../minimp3.h"
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+typedef int (*PARSE_GET_FILE_CB)(void *user, char **file_name);
+typedef int (*PARSE_INFO_CB)(void *user, char *file_name, int rate, int mp3_channels, float duration);
+
 typedef struct decoder
 {
-    CRITICAL_SECTION mp3_lock;
-    const char *file_name;
-    short *mp3_buf;
-    int mp3_size, mp3_pos, mp3_allocated, mp3_file_size, mp3_rate, mp3_channels;
+    mp3dec_t mp3d;
+    mp3dec_frame_info_t info;
+    uint8_t *mp3_buf;
+    size_t mp3_size, pos;
+    int file, pcm_bytes, pcm_copied, mp3_rate, mp3_channels;
     float mp3_duration;
-    HANDLE mp3_open_thread;
+    float spectrum[32][2]; // for visualization
+    short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
 } decoder;
 
 extern decoder _dec;
 
-int preload_mp3(decoder *dec, const char *file_name);
+int open_dec(decoder *dec, const char *file_name);
+int close_dec(decoder *dec);
+void decode_samples(decoder *dec, uint8_t *buf, int bytes);
+void start_parser(PARSE_GET_FILE_CB fcb, void *fcb_user, PARSE_INFO_CB icb, void *icb_user);
 
 #ifdef __cplusplus
 }
--- a/player/player.cpp
+++ b/player/player.cpp
@@ -39,6 +39,7 @@
 static std::map<std::string, int> _previews;
 static std::vector<std::string> _playlist;
 static void *_render;
+decoder _dec;
 
 static int load_image(const stbi_uc *data, int len)
 {
@@ -159,7 +160,9 @@
             if (nk_button_label(ctx, "Play") && _selected < (int)_playlist.size())
             {
                 _play_state = 1;
-                preload_mp3(&_dec, _playlist[_selected].c_str());
+                sdl_audio_set_dec(_render, 0);
+                open_dec(&_dec, _playlist[_selected].c_str());
+                sdl_audio_set_dec(_render, &_dec);
             }
         } else
         {
@@ -166,6 +169,7 @@
             if (nk_button_label(ctx, "Stop"))
             {
                 _play_state = 0;
+                sdl_audio_set_dec(_render, 0);
                 //stop();
             }
         }
@@ -199,7 +203,6 @@
 
 int main(int argc, char *argv[])
 {
-    InitializeCriticalSection(&_dec.mp3_lock);
     sdl_audio_init(&_render, 44100, 2, 0, 0);
     init();
     for (int i = 1; i < argc; i++)