Optimize busses; add samplerate changing library
This commit is contained in:
parent
8f6c8774de
commit
5da19ec407
2
Makefile
2
Makefile
|
@ -84,7 +84,7 @@ ifeq ($(OS), WIN32)
|
||||||
EXT = .exe
|
EXT = .exe
|
||||||
else
|
else
|
||||||
LINKER_FLAGS = $(QFLAGS) -L/usr/local/lib
|
LINKER_FLAGS = $(QFLAGS) -L/usr/local/lib
|
||||||
ELIBS = engine pthread yughc portaudio asound glfw3 c m dl
|
ELIBS = engine pthread yughc portaudio asound glfw3 c m dl samplerate
|
||||||
CLIBS =
|
CLIBS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -120,11 +120,11 @@ duk_ret_t duk_cmd(duk_context *duk) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 14:
|
case 14:
|
||||||
play_sound(make_sound(duk_to_string(duk, 1)));
|
play_oneshot(make_sound(duk_to_string(duk, 1)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 15:
|
case 15:
|
||||||
|
music_stop();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 16:
|
case 16:
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include "music.h"
|
#include "music.h"
|
||||||
#include "stb_vorbis.h"
|
#include "stb_vorbis.h"
|
||||||
|
|
||||||
|
#include "samplerate.h"
|
||||||
|
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
|
||||||
#include "mix.h"
|
#include "mix.h"
|
||||||
|
@ -47,27 +49,53 @@ void new_samplerate(short *in, short *out, int n, int ch, int sr_in, int sr_out)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wav change_samplerate(struct wav w, int rate)
|
static struct wav change_channels(struct wav w, int ch)
|
||||||
{
|
{
|
||||||
//int samples = sizeof(short) * w.ch * w.frames;
|
short *data = w.data;
|
||||||
//short *new = malloc(samples);
|
int samples = ch * w.frames;
|
||||||
//new_samplerate(w.data, new,
|
short *new = malloc(sizeof(short)*samples);
|
||||||
|
|
||||||
|
if (ch > w.ch) {
|
||||||
|
/* Sets all new channels equal to the first one */
|
||||||
|
for (int i = 0; i < w.frames; i++) {
|
||||||
|
for (int j = 0; j < ch; j++)
|
||||||
|
new[i*ch+j] = data[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Simple method; just use first N channels present in wav */
|
||||||
|
for (int i = 0; i < w.frames; i++)
|
||||||
|
for (int j = 0; j < ch; j++)
|
||||||
|
new[i*ch+j] = data[i*ch+j];
|
||||||
|
}
|
||||||
|
|
||||||
|
free (w.data);
|
||||||
|
w.data = new;
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
//SDL_AudioStream *stream = SDL_NewAudioStream(AUDIO_S16, w.ch, w.samplerate, AUDIO_S16, w.ch, rate);
|
static struct wav change_samplerate(struct wav w, int rate)
|
||||||
//SDL_AudioStreamPut(stream, w.data, w.frames*w.ch*sizeof(short));
|
{
|
||||||
|
float ratio = (float)rate/w.samplerate;
|
||||||
|
int outframes = w.frames * ratio;
|
||||||
|
SRC_DATA ssrc;
|
||||||
|
float floatdata[w.frames*w.ch];
|
||||||
|
src_short_to_float_array(w.data, floatdata, w.frames*w.ch);
|
||||||
|
float resampled[w.ch*outframes];
|
||||||
|
|
||||||
int oldframes = w.frames;
|
ssrc.data_in = floatdata;
|
||||||
w.frames *= (float)rate/w.samplerate;
|
ssrc.data_out = resampled;
|
||||||
int samples = sizeof(short) * w.ch * w.frames;
|
ssrc.input_frames = w.frames;
|
||||||
w.samplerate = rate;
|
ssrc.output_frames = outframes;
|
||||||
short *new = malloc(samples);
|
ssrc.src_ratio = ratio;
|
||||||
//SDL_AudioStreamGet(stream, new, samples);
|
|
||||||
|
src_simple(&ssrc, SRC_SINC_BEST_QUALITY, w.ch);
|
||||||
|
|
||||||
|
short *newdata = malloc(sizeof(short)*outframes*w.ch);
|
||||||
|
src_float_to_short_array(resampled, newdata, outframes*w.ch);
|
||||||
|
|
||||||
free(w.data);
|
free(w.data);
|
||||||
w.data = new;
|
w.data = newdata;
|
||||||
//SDL_FreeAudioStream(stream);
|
w.samplerate = rate;
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
@ -165,11 +193,17 @@ struct wav *make_sound(const char *wav)
|
||||||
struct wav mwav;
|
struct wav mwav;
|
||||||
mwav.data = drwav_open_file_and_read_pcm_frames_s16(wav, &mwav.ch, &mwav.samplerate, &mwav.frames, NULL);
|
mwav.data = drwav_open_file_and_read_pcm_frames_s16(wav, &mwav.ch, &mwav.samplerate, &mwav.frames, NULL);
|
||||||
|
|
||||||
if (mwav->samplerate != SAMPLERATE) {
|
|
||||||
YughInfo("Changing samplerate of %s.", wav);
|
if (mwav.samplerate != SAMPLERATE) {
|
||||||
|
YughInfo("Changing samplerate of %s from %d to %d.", wav, mwav.samplerate, 48000);
|
||||||
mwav = change_samplerate(mwav, 48000);
|
mwav = change_samplerate(mwav, 48000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mwav.ch != CHANNELS) {
|
||||||
|
YughInfo("Changing channels of %s from %d to %d.", wav, mwav.ch, CHANNELS);
|
||||||
|
//mwav = change_channels(mwav, CHANNELS);
|
||||||
|
}
|
||||||
|
|
||||||
mwav.gain = 1.f;
|
mwav.gain = 1.f;
|
||||||
|
|
||||||
struct wav *newwav = malloc(sizeof(*newwav));
|
struct wav *newwav = malloc(sizeof(*newwav));
|
||||||
|
@ -205,6 +239,7 @@ void play_oneshot(struct wav *wav) {
|
||||||
new->bus = first_free_bus(dsp_filter(new, sound_fillbuf));
|
new->bus = first_free_bus(dsp_filter(new, sound_fillbuf));
|
||||||
new->playing=1;
|
new->playing=1;
|
||||||
new->loop=0;
|
new->loop=0;
|
||||||
|
new->frame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sound *play_sound(struct wav *wav)
|
struct sound *play_sound(struct wav *wav)
|
||||||
|
@ -301,9 +336,7 @@ void sound_fillbuf(struct sound *s, short *buf, int n)
|
||||||
|
|
||||||
short *in = s->data->data;
|
short *in = s->data->data;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
for (int j = 0; j < 2; j++) {
|
for (int j = 0; j < CHANNELS; j++) buf[i*CHANNELS+j] = in[s->frame+j] * gainmult;
|
||||||
buf[i*2+j] = in[s->frame+j] * gainmult;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->frame++;
|
s->frame++;
|
||||||
if (s->frame == s->data->frames) {
|
if (s->frame == s->data->frames) {
|
||||||
|
@ -313,6 +346,7 @@ void sound_fillbuf(struct sound *s, short *buf, int n)
|
||||||
s->frame = 0;
|
s->frame = 0;
|
||||||
} else {
|
} else {
|
||||||
bus_free(s->bus);
|
bus_free(s->bus);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#define SOUND_H
|
#define SOUND_H
|
||||||
|
|
||||||
struct circbuf;
|
struct circbuf;
|
||||||
struct SDL_AudioStream;
|
|
||||||
|
|
||||||
struct Mix_Chunk {
|
struct Mix_Chunk {
|
||||||
int i;
|
int i;
|
||||||
|
@ -23,16 +22,15 @@ struct soundstream {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct soundconvstream {
|
struct soundconvstream {
|
||||||
// SDL_AudioStream *srconv;
|
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct soundstream *soundstream_make();
|
struct soundstream *soundstream_make();
|
||||||
|
|
||||||
/* A playing sound;
|
/* A playing sound */
|
||||||
struct sound {
|
struct sound {
|
||||||
int loop;
|
int loop; /* How many times to loop */
|
||||||
unsigned int frame;
|
unsigned int frame; /* Pointing to the current frame on the wav */
|
||||||
int playing;
|
int playing;
|
||||||
float gain;
|
float gain;
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,7 @@ struct dsp_filter dsp_filter(void *data, void (*filter)(void *data, short *out,
|
||||||
struct dsp_filter new;
|
struct dsp_filter new;
|
||||||
new.data = data;
|
new.data = data;
|
||||||
new.filter = filter;
|
new.filter = filter;
|
||||||
|
new.inputs = 0;
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "dsp.h"
|
#include "dsp.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
static struct bus bus[256];
|
static struct bus bus[256];
|
||||||
static int first = 0; /* First bus available */
|
static int first = 0; /* First bus available */
|
||||||
static int first_on = -1;
|
//static struct bus *first_on = NULL;
|
||||||
|
static int first_on = -1; /* First bus to fill buffer with */
|
||||||
short mastermix[BUF_FRAMES*CHANNELS];
|
short mastermix[BUF_FRAMES*CHANNELS];
|
||||||
|
|
||||||
void mixer_init() {
|
void mixer_init() {
|
||||||
|
@ -22,46 +24,44 @@ void mixer_init() {
|
||||||
|
|
||||||
struct bus *first_free_bus(struct dsp_filter in) {
|
struct bus *first_free_bus(struct dsp_filter in) {
|
||||||
if (first == -1) return NULL;
|
if (first == -1) return NULL;
|
||||||
struct bus *ret = bus[first];
|
int ret = first;
|
||||||
first = ret->next;
|
first = bus[ret].next;
|
||||||
ret->on = 1;
|
|
||||||
ret->in = in;
|
|
||||||
|
|
||||||
ret->next = first_on;
|
bus[ret].on = 1;
|
||||||
first_on = ret->id;
|
bus[ret].in = in;
|
||||||
|
|
||||||
return ret;
|
if (first_on != -1) bus[first_on].prev = ret;
|
||||||
|
|
||||||
|
bus[ret].next = first_on;
|
||||||
|
bus[ret].prev = -1;
|
||||||
|
first_on = ret;
|
||||||
|
|
||||||
|
return &bus[ret];
|
||||||
}
|
}
|
||||||
|
|
||||||
void bus_free(struct bus *bus)
|
void bus_free(struct bus *b)
|
||||||
{
|
{
|
||||||
bus->next = first;
|
if (first_on == b->id) first_on = b->next;
|
||||||
bus->on = 0;
|
if (b->next != -1) bus[b->next].prev = b->prev;
|
||||||
first = bus->id;
|
if (b->prev != -1) bus[b->prev].next = b->next;
|
||||||
|
|
||||||
|
b->next = first;
|
||||||
|
first = b->id;
|
||||||
|
b->on = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bus_fill_buffers(short *master, int n) {
|
void bus_fill_buffers(short *master, int n) {
|
||||||
int curbus = first_one
|
int curbus = first_on;
|
||||||
|
if (curbus == -1) return;
|
||||||
memset(master, 0, BUF_FRAMES*CHANNELS*sizeof(short));
|
memset(master, 0, BUF_FRAMES*CHANNELS*sizeof(short));
|
||||||
while (bus[curbus].next != -1) {
|
|
||||||
|
while (curbus != -1) {
|
||||||
|
int nextbus = bus[curbus].next; /* Save this in case busses get changed during fill */
|
||||||
dsp_run(bus[curbus].in, bus[curbus].buf, BUF_FRAMES);
|
dsp_run(bus[curbus].in, bus[curbus].buf, BUF_FRAMES);
|
||||||
for (int i = 0; i < BUF_FRAMES*CHANNELS; i++)
|
for (int i = 0; i < BUF_FRAMES*CHANNELS; i++)
|
||||||
master[i] += bus[curbus].buf[i];
|
master[i] += bus[curbus].buf[i];
|
||||||
|
|
||||||
curbus = bus[curbus].next;
|
curbus = nextbus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
for (int i = 0; i < 256; i++) {
|
|
||||||
if (bus[i].on != 1) continue;
|
|
||||||
dsp_run(bus[i].in, bus[i].buf, BUF_FRAMES);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j < 256; j++) {
|
|
||||||
if (!bus[j].on) continue;
|
|
||||||
for (int i = 0; i < BUF_FRAMES*CHANNELS; i++) {
|
|
||||||
master[i] += bus[j].buf[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,8 @@ void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n)
|
||||||
dsp_pan(&music_pan, out, n);
|
dsp_pan(&music_pan, out, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct bus *musicbus;
|
||||||
|
|
||||||
void play_song(const char *midi, const char *sf)
|
void play_song(const char *midi, const char *sf)
|
||||||
{
|
{
|
||||||
gsong.midi = tml_load_filename(midi);
|
gsong.midi = tml_load_filename(midi);
|
||||||
|
@ -85,7 +87,7 @@ void play_song(const char *midi, const char *sf)
|
||||||
|
|
||||||
cursong.data = &gsong;
|
cursong.data = &gsong;
|
||||||
cursong.filter = dsp_midi_fillbuf;
|
cursong.filter = dsp_midi_fillbuf;
|
||||||
first_free_bus(cursong);
|
musicbus = first_free_bus(cursong);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,7 +98,7 @@ void music_play()
|
||||||
|
|
||||||
void music_stop()
|
void music_stop()
|
||||||
{
|
{
|
||||||
|
bus_free(musicbus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void music_volume()
|
void music_volume()
|
||||||
|
|
|
@ -14,6 +14,7 @@ struct dsp_midi_song {
|
||||||
extern float music_pan;
|
extern float music_pan;
|
||||||
|
|
||||||
void play_song(const char *midi, const char *sf);
|
void play_song(const char *midi, const char *sf);
|
||||||
|
void music_stop();
|
||||||
void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n);
|
void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue