Using Erik's example code (modified) to do sample rate conversion
authorDavid Griffith <dave@661.org>
Sat, 25 Apr 2015 09:58:10 +0000 (02:58 -0700)
committerDavid Griffith <dave@661.org>
Sat, 25 Apr 2015 09:58:10 +0000 (02:58 -0700)
Makefile
src/curses/ux_audio.c

index 6b7c92456ea9752124d04f51117fbd6ee5a7fe2e..cc8645438250ea31bd96839211849628f1bd81af 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,8 +8,8 @@ CC = gcc
 # These are good for regular use.
 #OPTS = -O2 -fomit-frame-pointer -falign-functions=2 -falign-loops=2 -falign-jumps=2
 # These are handy for debugging.
-#OPTS = -g -Wall
 OPTS = -g
+#OPTS = -g -Wall -Wextra
 
 # Define where you want Frotz installed (typically /usr/local).
 #
@@ -64,6 +64,17 @@ CURSES = -lncurses
 #
 #NO_MEMMOVE = yes
 
+# Default sample rate for sound effects.
+# All modern sound interfaces can be expected to support 44100 Hz sample 
+# rates.  Earlier ones, particularly ones in Sun 4c workstations support 
+# only up to 8000 Hz.
+SAMPLERATE = 44100
+
+# Audio buffer size in frames
+BUFFSIZE = 512
+
+# Default sample rate converter type
+DEFAULT_CONVERTER = SRC_SINC_MEDIUM_QUALITY
 
 #########################################################################
 # This section is where Frotz is actually built.
@@ -178,10 +189,13 @@ $(CURSES_OBJECT): %.o: %.c
 #
 defines: defines.h
 defines.h:
-       @echo "Sound support: $(SOUND)"
+       @echo "Generating defines.h"
        @echo "#define VERSION \"$(VERSION)\"" > $(CURSES_DIR)/defines.h
        @echo "#define CONFIG_DIR \"$(CONFIG_DIR)\"" >> $(CURSES_DIR)/defines.h
        @echo "#define SOUND \"$(SOUND)\"" >> src/curses/defines.h
+       @echo "#define SAMPLERATE $(SAMPLERATE)" >> src/curses/defines.h
+       @echo "#define BUFFSIZE $(BUFFSIZE)" >> src/curses/defines.h
+       @echo "#define DEFAULT_CONVERTER $(DEFAULT_CONVERTER)" >> src/curses/defines.h
 
 ifeq ($(SOUND), none)
        @echo "#define NO_SOUND" >> $(CURSES_DIR)/defines.h
index b10c88d06f9b58f5e159868689a7db359f0f5885..df52d5beb64a538cc396d40185d6939da4a9af49 100644 (file)
 
 #include <ao/ao.h>
 #include <sndfile.h>
+#include <samplerate.h>
 #include <vorbis/codec.h>
 #include <vorbis/vorbisfile.h>
 #include <libmodplug/modplug.h>
 
-//#define BUFFSIZE 4096
-#define BUFFSIZE 512
-#define SAMPLERATE 44100
 #define MAX(x,y) ((x)>(y)) ? (x) : (y)
 #define MIN(x,y) ((x)<(y)) ? (x) : (y)
 
@@ -78,14 +76,13 @@ static sem_t                playaiff_okay;
 bool    bleep_playing = FALSE;
 bool   bleep_stop = FALSE;
 
-float  *musicbuffer;
-
-float  *bleepbuffer;
+short  *bleepbuffer;
 int    bleepchannels;
-int    bleeprate;
+int    bleepsamples;
 int    bleepcount;
 int    bleepnum;
 
+float  *musicbuffer;
 int    musiccount;
 
 
@@ -113,7 +110,7 @@ void os_init_sound(void)
        exit(1);
     }
 
-    bleepbuffer = malloc(BUFFSIZE * 2 * sizeof(float));
+    bleepbuffer = malloc(BUFFSIZE * 2 * sizeof(short));
     if (bleepbuffer == NULL) {
        printf("Unable to malloc bleepbuffer\n");
        exit(1);
@@ -296,7 +293,7 @@ static void *mixer(void *arg)
         pthread_mutex_lock(&mutex);     /* Acquire mutex */
 
        format.channels = bleepchannels;
-       format.rate = bleeprate;
+       format.rate = SAMPLERATE;
        if (bleep_playing && device == NULL) {
            device = ao_open_live(default_driver, &format, NULL);
            if (device == NULL) {
@@ -304,8 +301,7 @@ static void *mixer(void *arg)
            }
        }
 
-        floattopcm16(shortbuffer, bleepbuffer, BUFFSIZE * 2);
-        ao_play(device, (char *) shortbuffer, bleepcount * 2);
+        ao_play(device, (char *) bleepbuffer, bleepsamples);
 
        if (!bleep_playing) {
            ao_close(device);
@@ -379,17 +375,22 @@ static int mypower(int base, int exp) {
  */
 void *playaiff(EFFECT *raw_effect)
 {
-    int frames_read;
-    int count;
-    sf_count_t toread;
     long filestart;
 
     int volcount;
     int volfactor;
 
+    float *floatbuffer;
+    float *floatbuffer2;
+
     SNDFILE     *sndfile;
     SF_INFO     sf_info;
 
+    SRC_STATE  *src_state;
+    SRC_DATA   src_data;
+    int                error;
+    sf_count_t output_count = 0;
+
     EFFECT myeffect = *raw_effect;
 
     sem_post(&playaiff_okay);
@@ -405,34 +406,71 @@ void *playaiff(EFFECT *raw_effect)
     if (myeffect.vol > 8) myeffect.vol = 8;
     volfactor = mypower(2, -myeffect.vol + 8);
 
-    frames_read = 0;
-    toread = sf_info.frames * sf_info.channels;
+    floatbuffer = malloc(BUFFSIZE * sf_info.channels * sizeof(float));
+    floatbuffer2 = malloc(BUFFSIZE * sf_info.channels * sizeof(float));
+
+    /* Set up for conversion */
+    if ((src_state = src_new(DEFAULT_CONVERTER, sf_info.channels, &error)) == NULL) {
+       printf("Error: src_new() failed: %s.\n", src_strerror(error));
+       exit(1);
+    }
+    src_data.end_of_input = 0;
+    src_data.input_frames = 0;
+    src_data.data_in = floatbuffer;
+    src_data.src_ratio = (1.0 * SAMPLERATE) / sf_info.samplerate;
+    src_data.data_out = floatbuffer2;
+    src_data.output_frames = BUFFSIZE / sf_info.channels;
 
     bleepchannels = sf_info.channels;
-    bleeprate = sf_info.samplerate;
 
     bleep_playing = TRUE;
-    while (toread > 0) {
-       if (bleep_stop) break;
 
+    while (1) {
+       /* Check if we're being told to stop */
+       if (bleep_stop) break;
        sem_wait(&audio_empty);
        pthread_mutex_lock(&mutex);
 
-       if (toread < BUFFSIZE * sf_info.channels)
-           count = toread;
-       else
-           count = BUFFSIZE * sf_info.channels;
-        frames_read = sf_read_float(sndfile, bleepbuffer, count);
-       for (volcount = 0; volcount <= frames_read; volcount++) {
-           bleepbuffer[volcount] /= volfactor;
+       /* if floatbuffer is empty, refill it */
+       if (src_data.input_frames == 0) {
+           src_data.input_frames = sf_readf_float(sndfile, floatbuffer, BUFFSIZE / sf_info.channels);
+           src_data.data_in = floatbuffer;
+           /* mark end of input */
+           if (src_data.input_frames < BUFFSIZE / sf_info.channels)
+               src_data.end_of_input = SF_TRUE;
        }
 
-       bleepcount = frames_read;
-       toread = toread - frames_read;
+       /* do the sample rate conversion */
+       if ((error = src_process(src_state, &src_data))) {
+           printf("Error: %s\n", src_strerror(error));
+           exit(1);
+       }
+
+       bleepsamples = src_data.output_frames_gen * sizeof(short) * sf_info.channels;
+
+       /* if that's all, terminate and signal that we're done */
+       if (src_data.end_of_input && src_data.output_frames_gen == 0) {
+           pthread_mutex_unlock(&mutex);
+           sem_post(&audio_full);
+           break;
+       }
+
+       /* convert floats to pcm16 and put them in bleepbuffer */
+        floattopcm16(bleepbuffer, floatbuffer2, src_data.output_frames_gen * sf_info.channels);
+
+       /* adjust volume */
+       for (volcount = 0; volcount <= bleepsamples; volcount++)
+           bleepbuffer[volcount] /= volfactor;
+
+       /* get ready for the next chunk */
+        output_count += src_data.output_frames_gen;
+        src_data.data_in += src_data.input_frames_used * sf_info.channels;
+        src_data.input_frames -= src_data.input_frames_used;
 
        pthread_mutex_unlock(&mutex);
        sem_post(&audio_full);
     }
+
     bleep_stop = FALSE;
     bleep_playing = FALSE;