cleanup: float stuff

This commit is contained in:
bnnm 2024-08-25 10:52:21 +02:00
parent aec9e9a723
commit 28c6d64693
6 changed files with 86 additions and 41 deletions

View File

@ -59,12 +59,25 @@ static void update_position(libvgmstream_priv_t* priv) {
pos->current = 0;
}
static int get_sample_size(libvgmstream_sample_t sample_type) {
switch(sample_type) {
case LIBVGMSTREAM_SAMPLE_PCM24:
case LIBVGMSTREAM_SAMPLE_PCM32:
case LIBVGMSTREAM_SAMPLE_FLOAT:
return 0x04;
case LIBVGMSTREAM_SAMPLE_PCM16:
default:
return 0x02;
}
}
static void update_format_info(libvgmstream_priv_t* priv) {
libvgmstream_format_t* fmt = &priv->fmt;
VGMSTREAM* v = priv->vgmstream;
fmt->sample_size = 0x02;
fmt->sample_type = LIBVGMSTREAM_SAMPLE_PCM16;
//fmt->sample_type = LIBVGMSTREAM_SAMPLE_FLOAT;
fmt->sample_size = get_sample_size(fmt->sample_type);
fmt->sample_rate = v->sample_rate;
fmt->subsong_index = v->stream_index;

View File

@ -24,9 +24,13 @@ static bool reset_buf(libvgmstream_priv_t* priv) {
priv->buf.input_channels = priv->buf.output_channels;
priv->buf.sample_size = sizeof(sample_t);
//priv->buf.sample_size = sizeof(float);
priv->buf.max_samples = INTERNAL_BUF_SAMPLES;
priv->buf.max_bytes = priv->buf.max_samples * priv->buf.sample_size * priv->buf.input_channels;
priv->buf.data = malloc(priv->buf.max_bytes);
int max_sample_size = sizeof(sample_t);
//int max_sample_size = sizeof(float);
int max_bytes = priv->buf.max_samples * max_sample_size * priv->buf.input_channels;
priv->buf.data = malloc(max_bytes);
if (!priv->buf.data) return false;
priv->buf.initialized = true;

View File

@ -25,7 +25,6 @@ typedef struct {
/* config */
int input_channels;
int output_channels;
int max_bytes;
int max_samples;
int sample_size;

View File

@ -86,9 +86,8 @@ void mixer_process(mixer_t* mixer, sbuf_t* sbuf, int32_t current_pos) {
mixer->current_subpos = current_pos;
}
// upgrade buf for mixing (somehow using float buf rather than int32 is faster?)
// remix to temp buf for mixing (somehow using float buf rather than int32 is faster?)
sbuf_copy_to_f32(mixer->mixbuf, sbuf);
//sbuf_copy_s16_to_f32(mixer->mixbuf, outbuf, sample_count, mixer->input_channels);
// apply mixing ops in order. current_channels may increase or decrease per op
// - 2ch w/ "1+2,1u" = ch1+ch2, ch1(add and push rest) = 3ch: ch1' ch1+ch2 ch2
@ -112,8 +111,9 @@ void mixer_process(mixer_t* mixer, sbuf_t* sbuf, int32_t current_pos) {
}
}
// downgrade mix to original output (with new channels)
sbuf->channels = mixer->output_channels;
// setup + remix to output buf (buf is expected to be big enough to handle config)
sbuf->channels = mixer->output_channels; // new channels
//if (force_float) sbuf->fmt = SFMT_FLT; // new format
//if (force_pcm16) sbuf->fmt = SFMT_PCM16; // new format
sbuf_copy_from_f32(sbuf, mixer->mixbuf);
//sbuf_copy_f32_to_s16(outbuf, mixer->mixbuf, sbuf->filled, mixer->output_channels);
}

View File

@ -1,5 +1,6 @@
#include <stdlib.h>
#include <string.h>
//#include <math.h>
#include "../util.h"
#include "sbuf.h"
@ -20,29 +21,6 @@ void sbuf_init_f32(sbuf_t* sbuf, float* buf, int samples, int channels) {
sbuf->fmt = SFMT_F32;
}
//TODO decide if using float 1.0 style or 32767 style (fuzzy PCM when doing that)
//TODO: maybe use macro-style templating (but kinda ugly)
void sbuf_copy_to_f32(float* dst, sbuf_t* sbuf) {
switch(sbuf->fmt) {
case SFMT_S16: {
int16_t* buf = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = (float)buf[s]; // / 32767.0f
}
break;
}
case SFMT_F32: {
float* buf = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = buf[s];
}
break;
}
default:
break;
}
}
/* when casting float to int, value is simply truncated:
* - (int)1.7 = 1, (int)-1.7 = -1
@ -52,20 +30,68 @@ void sbuf_copy_to_f32(float* dst, sbuf_t* sbuf) {
* - (((int) (f1 + 32768.5)) - 32768)
* - etc
* but since +-1 isn't really audible we'll just cast, as it's the fastest
*
* Regular C float-to-int casting ("int i = (int)f") is somewhat slow due to IEEE
* float requirements, but C99 adds some faster-but-less-precise casting functions.
* MSVC added this in VS2015 (_MSC_VER 1900) but doesn't seem inlined and is very slow.
* It's slightly faster (~5%) but causes fuzzy PCM<>float<>PCM conversions.
*/
static inline int float_to_int(float val) {
#if 1
return (int)val;
#elif defined(_MSC_VER)
return (int)val;
#else
return lrintf(val);
#endif
}
//TODO decide if using float 1.0 style or 32767 style (fuzzy PCM when doing that)
//TODO: maybe use macro-style templating (but kinda ugly)
void sbuf_copy_to_f32(float* dst, sbuf_t* sbuf) {
switch(sbuf->fmt) {
case SFMT_S16: {
int16_t* src = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = (float)src[s]; // / 32767.0f
}
break;
}
case SFMT_FLT:
case SFMT_F32: {
float* src = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s];
}
break;
}
default:
break;
}
}
void sbuf_copy_from_f32(sbuf_t* sbuf, float* src) {
switch(sbuf->fmt) {
case SFMT_S16: {
int16_t* buf = sbuf->buf;
int16_t* dst = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
buf[s] = clamp16( src[s]); // * 32767.0f
dst[s] = clamp16(float_to_int(src[s]));
}
break;
}
case SFMT_F32: {
float* buf = sbuf->buf;
float* dst = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
buf[s] = src[s];
dst[s] = src[s];
}
break;
}
case SFMT_FLT: {
float* dst = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s] / 32768.0f;
}
break;
}

View File

@ -3,26 +3,29 @@
#include "../streamtypes.h"
/* interleaved: buffer for all channels = [ch*s] = (ch1 ch2 ch1 ch2 ch1 ch2 ch1 ch2 ...) */
/* planar: buffer per channel = [ch][s] = (c1 c1 c1 c1 ...) (c2 c2 c2 c2 ...) */
/* All types are interleaved (buffer for all channels = [ch*s] = ch1 ch2 ch1 ch2 ch1 ch2 ...)
* rather than planar (buffer per channel = [ch][s] = c1 c1 c1 c1 ... c2 c2 c2 c2 ...) */
typedef enum {
SFMT_NONE,
SFMT_S16,
SFMT_S16, /* standard PCM16 */
//SFMT_S24,
//SFMT_S32,
SFMT_F32,
SFMT_F32, /* pcm-like float (+-32768), for internal use (simpler pcm > f32 plus some decoders use this) */
SFMT_FLT, /* standard float (+-1.0), for external players */
} sfmt_t;
/* simple buffer info for internal mixing
* meant to held existing sound buffer pointers rather than alloc'ing directly (some ops will swap/move its internals) */
typedef struct {
void* buf; /* current sample buffer */
sfmt_t fmt; /* buffer type */
int channels; /* interleaved step or planar buffers */
int samples; /* max samples */
int filled; /* samples in buffer */
//int planar;
} sbuf_t;
void sbuf_init_s16(sbuf_t* sbuf, int16_t* buf, int samples, int channels);
void sbuf_init_f32(sbuf_t* sbuf, float* buf, int samples, int channels);