mirror of
https://github.com/Relintai/sfw.git
synced 2025-04-14 09:10:47 +02:00
Format audio.cpp.
This commit is contained in:
parent
679ef20c53
commit
6870ecfbec
@ -1,8 +1,11 @@
|
||||
// @fixme: really shutdown audio & related threads before quitting. ma_dr_wav crashes.
|
||||
|
||||
|
||||
// encapsulate ma_dr_wav,ma_dr_mp3,stbvorbis and some buffer with the sts_mixer_stream_t
|
||||
enum { UNK, WAV, OGG, MP1, MP3 };
|
||||
enum { UNK,
|
||||
WAV,
|
||||
OGG,
|
||||
MP1,
|
||||
MP3 };
|
||||
typedef struct {
|
||||
int type;
|
||||
union {
|
||||
@ -25,7 +28,8 @@ static void downsample_to_mono_flt( int channels, float *buffer, int samples ) {
|
||||
float *output = buffer;
|
||||
while (samples-- > 0) {
|
||||
float mix = 0;
|
||||
for( int i = 0; i < channels; ++i ) mix += *buffer++;
|
||||
for (int i = 0; i < channels; ++i)
|
||||
mix += *buffer++;
|
||||
*output++ = (float)(mix / channels);
|
||||
}
|
||||
}
|
||||
@ -35,7 +39,8 @@ static void downsample_to_mono_s16( int channels, short *buffer, int samples ) {
|
||||
short *output = buffer;
|
||||
while (samples-- > 0) {
|
||||
float mix = 0;
|
||||
for( int i = 0; i < channels; ++i ) mix += *buffer++;
|
||||
for (int i = 0; i < channels; ++i)
|
||||
mix += *buffer++;
|
||||
*output++ = (short)(mix / channels);
|
||||
}
|
||||
}
|
||||
@ -46,28 +51,37 @@ static bool refill_stream(sts_mixer_sample_t* sample, void* userdata) {
|
||||
mystream_t *stream = (mystream_t *)userdata;
|
||||
switch (stream->type) {
|
||||
default:
|
||||
break; case WAV: {
|
||||
int sl = sample->length / 2; /*sample->channels*/;
|
||||
if( stream->rewind ) stream->rewind = 0, ma_dr_wav_seek_to_pcm_frame(&stream->wav, 0);
|
||||
break;
|
||||
case WAV: {
|
||||
int sl = sample->length / 2; /*sample->channels*/
|
||||
;
|
||||
if (stream->rewind)
|
||||
stream->rewind = 0, ma_dr_wav_seek_to_pcm_frame(&stream->wav, 0);
|
||||
if (ma_dr_wav_read_pcm_frames_s16(&stream->wav, sl, (short *)stream->data) < sl) {
|
||||
ma_dr_wav_seek_to_pcm_frame(&stream->wav, 0);
|
||||
if (!stream->loop) return false;
|
||||
if (!stream->loop)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break; case MP3: {
|
||||
int sl = sample->length / 2; /*sample->channels*/;
|
||||
if( stream->rewind ) stream->rewind = 0, ma_dr_mp3_seek_to_pcm_frame(&stream->mp3_, 0);
|
||||
} break;
|
||||
case MP3: {
|
||||
int sl = sample->length / 2; /*sample->channels*/
|
||||
;
|
||||
if (stream->rewind)
|
||||
stream->rewind = 0, ma_dr_mp3_seek_to_pcm_frame(&stream->mp3_, 0);
|
||||
if (ma_dr_mp3_read_pcm_frames_f32(&stream->mp3_, sl, stream->dataf) < sl) {
|
||||
ma_dr_mp3_seek_to_pcm_frame(&stream->mp3_, 0);
|
||||
if (!stream->loop) return false;
|
||||
if (!stream->loop)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break; case OGG: {
|
||||
} break;
|
||||
case OGG: {
|
||||
stb_vorbis *ogg = (stb_vorbis *)stream->ogg;
|
||||
if( stream->rewind ) stream->rewind = 0, stb_vorbis_seek(stream->ogg, 0);
|
||||
if (stream->rewind)
|
||||
stream->rewind = 0, stb_vorbis_seek(stream->ogg, 0);
|
||||
if (stb_vorbis_get_samples_short_interleaved(ogg, 2, (short *)stream->data, sample->length) == 0) {
|
||||
stb_vorbis_seek(stream->ogg, 0);
|
||||
if (!stream->loop) return false;
|
||||
if (!stream->loop)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,13 +89,16 @@ static bool refill_stream(sts_mixer_sample_t* sample, void* userdata) {
|
||||
return true;
|
||||
}
|
||||
static void reset_stream(mystream_t *stream) {
|
||||
if( stream ) memset( stream->data, 0, sizeof(stream->data) ), stream->rewind = 1;
|
||||
if (stream)
|
||||
memset(stream->data, 0, sizeof(stream->data)), stream->rewind = 1;
|
||||
}
|
||||
|
||||
// load a (stereo) stream
|
||||
static bool load_stream(mystream_t *stream, const char *filename) {
|
||||
int datalen;
|
||||
char *data = vfs_load(filename, &datalen); if(!data) return false;
|
||||
char *data = vfs_load(filename, &datalen);
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
int error;
|
||||
int HZ = 44100;
|
||||
@ -89,13 +106,19 @@ static bool load_stream(mystream_t* stream, const char *filename) {
|
||||
stream->loop = true;
|
||||
if (stream->type == UNK && (stream->ogg = stb_vorbis_open_memory((const unsigned char *)data, datalen, &error, NULL))) {
|
||||
stb_vorbis_info info = stb_vorbis_get_info(stream->ogg);
|
||||
if( info.channels != 2 ) { puts("cannot stream ogg file. stereo required."); goto end; } // @fixme: upsample
|
||||
if (info.channels != 2) {
|
||||
puts("cannot stream ogg file. stereo required.");
|
||||
goto end;
|
||||
} // @fixme: upsample
|
||||
stream->type = OGG;
|
||||
stream->stream.sample.frequency = info.sample_rate;
|
||||
stream->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_16;
|
||||
}
|
||||
if (stream->type == UNK && ma_dr_wav_init_memory(&stream->wav, data, datalen, NULL)) {
|
||||
if( stream->wav.channels != 2 ) { puts("cannot stream wav file. stereo required."); goto end; } // @fixme: upsample
|
||||
if (stream->wav.channels != 2) {
|
||||
puts("cannot stream wav file. stereo required.");
|
||||
goto end;
|
||||
} // @fixme: upsample
|
||||
stream->type = WAV;
|
||||
stream->stream.sample.frequency = stream->wav.sampleRate;
|
||||
stream->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_16;
|
||||
@ -124,12 +147,15 @@ static bool load_stream(mystream_t* stream, const char *filename) {
|
||||
// load a (mono) sample
|
||||
static bool load_sample(sts_mixer_sample_t *sample, const char *filename) {
|
||||
int datalen;
|
||||
char *data = vfs_load(filename, &datalen); if(!data) return false;
|
||||
char *data = vfs_load(filename, &datalen);
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
int error;
|
||||
int channels = 0;
|
||||
|
||||
if( !channels ) for( ma_dr_wav w = {0}, *wav = &w; wav && ma_dr_wav_init_memory(wav, data, datalen, NULL); wav = 0 ) {
|
||||
if (!channels)
|
||||
for (ma_dr_wav w = { 0 }, *wav = &w; wav && ma_dr_wav_init_memory(wav, data, datalen, NULL); wav = 0) {
|
||||
channels = wav->channels;
|
||||
sample->frequency = wav->sampleRate;
|
||||
sample->audio_format = STS_MIXER_SAMPLE_FORMAT_16;
|
||||
@ -138,7 +164,8 @@ static bool load_sample(sts_mixer_sample_t* sample, const char *filename) {
|
||||
ma_dr_wav_read_pcm_frames_s16(wav, sample->length, (short *)sample->data);
|
||||
ma_dr_wav_uninit(wav);
|
||||
}
|
||||
if( !channels ) for( stb_vorbis *ogg = stb_vorbis_open_memory((const unsigned char *)data, datalen, &error, NULL); ogg; ogg = 0 ) {
|
||||
if (!channels)
|
||||
for (stb_vorbis *ogg = stb_vorbis_open_memory((const unsigned char *)data, datalen, &error, NULL); ogg; ogg = 0) {
|
||||
stb_vorbis_info info = stb_vorbis_get_info(ogg);
|
||||
channels = info.channels;
|
||||
sample->frequency = info.sample_rate;
|
||||
@ -153,7 +180,8 @@ static bool load_sample(sts_mixer_sample_t* sample, const char *filename) {
|
||||
}
|
||||
ma_dr_mp3_config mp3_cfg = { 2, 44100 };
|
||||
ma_uint64 mp3_fc;
|
||||
if( !channels ) for( short *fbuf = ma_dr_mp3_open_memory_and_read_pcm_frames_s16(data, datalen, &mp3_cfg, &mp3_fc, NULL); fbuf ; fbuf = 0 ) {
|
||||
if (!channels)
|
||||
for (short *fbuf = ma_dr_mp3_open_memory_and_read_pcm_frames_s16(data, datalen, &mp3_cfg, &mp3_fc, NULL); fbuf; fbuf = 0) {
|
||||
channels = mp3_cfg.channels;
|
||||
sample->frequency = mp3_cfg.sampleRate;
|
||||
sample->audio_format = STS_MIXER_SAMPLE_FORMAT_16;
|
||||
@ -182,13 +210,10 @@ static bool load_sample(sts_mixer_sample_t* sample, const char *filename) {
|
||||
if (sample->audio_format == STS_MIXER_SAMPLE_FORMAT_FLOAT) {
|
||||
downsample_to_mono_flt(channels, sample->data, sample->length);
|
||||
sample->data = REALLOC(sample->data, sample->length * sizeof(float));
|
||||
}
|
||||
else
|
||||
if( sample->audio_format == STS_MIXER_SAMPLE_FORMAT_16 ) {
|
||||
} else if (sample->audio_format == STS_MIXER_SAMPLE_FORMAT_16) {
|
||||
downsample_to_mono_s16(channels, sample->data, sample->length);
|
||||
sample->data = REALLOC(sample->data, sample->length * sizeof(short));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
puts("error!"); // @fixme
|
||||
}
|
||||
}
|
||||
@ -206,7 +231,8 @@ static sts_mixer_t mixer;
|
||||
static void audio_callback(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount) {
|
||||
int len = frameCount;
|
||||
sts_mixer_mix_audio(&mixer, pOutput, len / (sizeof(int32_t) / 4));
|
||||
(void)pDevice; (void)pInput;
|
||||
(void)pDevice;
|
||||
(void)pInput;
|
||||
// return len / (sizeof(int32_t) / 4);
|
||||
}
|
||||
|
||||
@ -311,10 +337,10 @@ audio_t audio_stream( const char *pathfile ) {
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
static float volume_clip = 1, volume_stream = 1, volume_master = 1;
|
||||
float audio_volume_clip(float gain) {
|
||||
if( gain >= 0 && gain <= 1 ) volume_clip = gain * gain;
|
||||
if (gain >= 0 && gain <= 1)
|
||||
volume_clip = gain * gain;
|
||||
// patch all live clips
|
||||
for (int i = 0, active = 0; i < STS_MIXER_VOICES; ++i) {
|
||||
if (mixer.voices[i].state != STS_MIXER_VOICE_STOPPED) // is_active?
|
||||
@ -324,7 +350,8 @@ float audio_volume_clip(float gain) {
|
||||
return sqrt(volume_clip);
|
||||
}
|
||||
float audio_volume_stream(float gain) {
|
||||
if( gain >= 0 && gain <= 1 ) volume_stream = gain * gain;
|
||||
if (gain >= 0 && gain <= 1)
|
||||
volume_stream = gain * gain;
|
||||
// patch all live streams
|
||||
for (int i = 0, active = 0; i < STS_MIXER_VOICES; ++i) {
|
||||
if (mixer.voices[i].state != STS_MIXER_VOICE_STOPPED) // is_active?
|
||||
@ -334,14 +361,17 @@ float audio_volume_stream(float gain) {
|
||||
return sqrt(volume_stream);
|
||||
}
|
||||
float audio_volume_master(float gain) {
|
||||
if( gain >= 0 && gain <= 1 ) volume_master = gain * gain;
|
||||
if (gain >= 0 && gain <= 1)
|
||||
volume_master = gain * gain;
|
||||
// patch global mixer
|
||||
mixer.gain = volume_master;
|
||||
return sqrt(volume_master);
|
||||
}
|
||||
int audio_mute(int mute) {
|
||||
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted");
|
||||
if( mute >= 0 && mute <= 1 ) muted = mute;
|
||||
static bool muted = 0;
|
||||
do_once muted = flag("--mute") || flag("--muted");
|
||||
if (mute >= 0 && mute <= 1)
|
||||
muted = mute;
|
||||
return muted;
|
||||
}
|
||||
int audio_muted() {
|
||||
@ -349,7 +379,8 @@ int audio_muted() {
|
||||
}
|
||||
|
||||
int audio_play_gain_pitch_pan(audio_t a, int flags, float gain, float pitch, float pan) {
|
||||
if(audio_muted()) return 1;
|
||||
if (audio_muted())
|
||||
return 1;
|
||||
|
||||
if (flags & AUDIO_IGNORE_MIXER_GAIN) {
|
||||
// do nothing, gain used as-is
|
||||
@ -366,11 +397,13 @@ int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, fl
|
||||
|
||||
if (a->is_clip) {
|
||||
int voice = sts_mixer_play_sample(&mixer, &a->clip, gain, pitch, pan);
|
||||
if( voice == -1 ) return 0; // all voices busy
|
||||
if (voice == -1)
|
||||
return 0; // all voices busy
|
||||
}
|
||||
if (a->is_stream) {
|
||||
int voice = sts_mixer_play_stream(&mixer, &a->stream.stream, gain);
|
||||
if( voice == -1 ) return 0; // all voices busy
|
||||
if (voice == -1)
|
||||
return 0; // all voices busy
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -451,7 +484,8 @@ static bool audio_queue_callback(sts_mixer_sample_t* sample, void* userdata) {
|
||||
static audio_queue_t *aq = 0;
|
||||
|
||||
do {
|
||||
while( !aq ) aq = (audio_queue_t*)thread_queue_consume(&queue_mutex, THREAD_QUEUE_WAIT_INFINITE);
|
||||
while (!aq)
|
||||
aq = (audio_queue_t *)thread_queue_consume(&queue_mutex, THREAD_QUEUE_WAIT_INFINITE);
|
||||
|
||||
int len = aq->avail > bytes ? bytes : aq->avail;
|
||||
memcpy(dst, (char *)aq->data + aq->cursor, len);
|
||||
@ -482,7 +516,8 @@ int audio_queue( const void *samples, int num_samples, int flags ) {
|
||||
float pitch = 1; // (0..N]
|
||||
float pan = 0; // [-1..1]
|
||||
|
||||
int bits = flags & AUDIO_8 ? 8 : flags & (AUDIO_32|AUDIO_FLOAT) ? 32 : 16;
|
||||
int bits = flags & AUDIO_8 ? 8 : flags & (AUDIO_32 | AUDIO_FLOAT) ? 32
|
||||
: 16;
|
||||
int channels = flags & AUDIO_2CH ? 2 : 1;
|
||||
int bytes_per_sample = channels * (bits / 8);
|
||||
int bytes = num_samples * bytes_per_sample;
|
||||
@ -494,13 +529,17 @@ int audio_queue( const void *samples, int num_samples, int flags ) {
|
||||
q.sample.data = reuse_ptr;
|
||||
|
||||
q.callback = audio_queue_callback;
|
||||
q.sample.frequency = flags & AUDIO_8KHZ ? 8000 : flags & AUDIO_11KHZ ? 11025 : flags & AUDIO_44KHZ ? 44100 : flags & AUDIO_32KHZ ? 32000 : 22050;
|
||||
q.sample.frequency = flags & AUDIO_8KHZ ? 8000 : flags & AUDIO_11KHZ ? 11025
|
||||
: flags & AUDIO_44KHZ ? 44100
|
||||
: flags & AUDIO_32KHZ ? 32000
|
||||
: 22050;
|
||||
q.sample.audio_format = flags & AUDIO_FLOAT ? STS_MIXER_SAMPLE_FORMAT_FLOAT : STS_MIXER_SAMPLE_FORMAT_16;
|
||||
q.sample.length = q.sample.frequency / (1000 / AUDIO_QUEUE_BUFFERING_MS); // num_samples;
|
||||
int bytes = q.sample.length * 2 * (flags & AUDIO_FLOAT ? 4 : 2);
|
||||
q.sample.data = memset(REALLOC(q.sample.data, bytes), 0, bytes);
|
||||
audio_queue_voice = sts_mixer_play_stream(&mixer, &q, gain * 1.f);
|
||||
if( audio_queue_voice < 0 ) return 0;
|
||||
if (audio_queue_voice < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
audio_queue_t *aq = MALLOC(sizeof(audio_queue_t) + (bytes << (channels == 1))); // dupe space if going to be converted from mono to stereo
|
||||
@ -522,7 +561,8 @@ int audio_queue( const void *samples, int num_samples, int flags ) {
|
||||
}
|
||||
}
|
||||
|
||||
while( !thread_queue_produce(&queue_mutex, aq, THREAD_QUEUE_WAIT_INFINITE) ) {}
|
||||
while (!thread_queue_produce(&queue_mutex, aq, THREAD_QUEUE_WAIT_INFINITE)) {
|
||||
}
|
||||
|
||||
return audio_queue_voice;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user