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++)