diff options
| author | XANTRONIX Development | 2022-02-15 20:53:24 -0500 | 
|---|---|---|
| committer | XANTRONIX Development | 2022-02-15 20:53:24 -0500 | 
| commit | e0fda7988c2cca763d92075a5d95f813a37b69f4 (patch) | |
| tree | e547109adad66235581ec60ea5836ad6e75b6f95 /src | |
| parent | 1fe063a6d66048e6f95d1f60a7d7f837799cefe7 (diff) | |
| download | xas-e0fda7988c2cca763d92075a5d95f813a37b69f4.tar.gz xas-e0fda7988c2cca763d92075a5d95f813a37b69f4.tar.bz2 xas-e0fda7988c2cca763d92075a5d95f813a37b69f4.zip | |
It's surprising this stuff compiles, but fuck it
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile | 4 | ||||
| -rw-r--r-- | src/spatial.c | 223 | 
2 files changed, 208 insertions, 19 deletions
| diff --git a/src/Makefile b/src/Makefile index b9e9150..7c26ac9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,9 +7,9 @@ CC		 = $(CROSS)cc  CFLAGS		+= -I$(INCLUDE_PATH)  LDFLAGS		+= -HEADERS		= audio.h riff.h mixer.h synth.h vox.h bank.h +HEADERS		= audio.h riff.h mixer.h synth.h vox.h bank.h spatial.h -OBJS		= audio.o riff.o mixer.o synth.o vox.o bank.o +OBJS		= audio.o riff.o mixer.o synth.o vox.o bank.o spatial.o  VERSION_MAJOR	= 0  VERSION_MINOR	= 0.1 diff --git a/src/spatial.c b/src/spatial.c index 809fce1..18173aa 100644 --- a/src/spatial.c +++ b/src/spatial.c @@ -10,24 +10,146 @@ static inline float dist(xas_spatial_coord a, xas_spatial_coord b) {                + powf(b.z - a.z, 2.0f), 0.5f);  } -static int buf_realloc(xas_spatial_scene *scene, void *buf) { -    float width = scene->observer.width, -          speed = scene->speed; +static int buffer_realloc(xas_spatial_scene *scene, +                          xas_spatial_buffer *buffer) { +    float seconds = scene->radius / scene->speed;      size_t sample_rate = scene->format.sample_rate,             stride      = scene->format.channels * scene->format.sample_size, -           count       = floorf(width / (speed / sample_rate)); +           count       = sample_rate * ceilf(seconds), +           total       = sizeof(xas_spatial_buffer) + stride * count; -    if ((buf = realloc(buf, stride * count)) == NULL) { -        goto error_realloc; +    if ((buffer = realloc(buffer, total)) == NULL) { +        goto error_realloc_buffer;      } -    scene->buf    = buf; -    scene->buflen = count; +    memset(buffer + 1, '\0', stride * count); + +    scene->buffer        = buffer; +    scene->buffer->index = 0; +    scene->buffer->size  = count;      return 0; -error_realloc: +error_realloc_buffer: +    return -1; +} + +static inline size_t sample_index(xas_spatial_scene *scene, float distance) { +    size_t index = floorf(distance / scene->speed / scene->format.sample_rate); + +    return (scene->buffer->index + index) % scene->buffer->size; +} + +static inline int16_t sample_scale(int16_t value, float distance) { +    return (int16_t)roundf((float)value * (1.0f / powf(distance, 2.0))); +} + +static void buffer_zero(xas_spatial_buffer *buffer, size_t count) { +    int16_t *dest = (int16_t *)buffer + 1; +    size_t i = buffer->index; + +    if (count > buffer->size) { +        count = buffer->size; +    } + +    while (count--) { +        if (i == buffer->size) { +            i = 0; +        } + +        dest[i*XAS_AUDIO_STEREO]   = 0; +        dest[i*XAS_AUDIO_STEREO+1] = 0; + +        i++; +    } +} + +static void buffer_copy(xas_spatial_buffer *buffer, +                        int16_t *dest, +                        size_t count) { +    int16_t *src = (int16_t *)buffer + 1; +    size_t i = buffer->index; + +    if (count > buffer->size) { +        count = buffer->size; +    } + +    while (count--) { +        if (i == buffer->size) { +            i = 0; +        } + +        dest[i*XAS_AUDIO_STEREO]   = src[i*XAS_AUDIO_STEREO]; +        dest[i*XAS_AUDIO_STEREO+1] = src[i*XAS_AUDIO_STEREO+1]; +    } +} + +ssize_t scene_fill(xas_spatial_scene *scene, +                   int16_t *output, +                   size_t count, +                   xas_audio_stream *source) { +    xas_spatial_buffer *buffer = scene->buffer; +    xas_spatial_object *obj    = scene->first; + +    size_t index_old = buffer->index; + +    int16_t *dest = (int16_t *)(scene->buffer + 1); + +    buffer_zero(buffer, count); + +    while (obj) { +        int16_t *src; + +        float distance_l = dist(scene->speaker_l, obj->coord), +              distance_r = dist(scene->speaker_r, obj->coord); + +        size_t index_l, +               index_r; + +        ssize_t readlen, +                i; + +        if (distance_l > scene->radius || distance_r > scene->radius) { +            continue; +        } + +        if ((readlen = xas_audio_stream_read(obj->source, +                                               (void **)&src, +                                               count)) < 0) { +            goto error_audio_stream_read; +        } + +        if (readlen > (ssize_t)buffer->size) { +            readlen = buffer->size; +        } + +        index_l = sample_index(scene, distance_l); +        index_r = sample_index(scene, distance_r); + +        for (i=0; i<readlen; i++) { +            int16_t value_l = sample_scale(src[i], distance_l), +                    value_r = sample_scale(src[i], distance_r); + +            if (buffer->index == buffer->size) { +                buffer->index = 0; +            } + +            dest[XAS_AUDIO_STEREO*index_l+i]   += value_l; +            dest[XAS_AUDIO_STEREO*index_r+i+1] += value_r; + +            buffer->index++; +        } + +        buffer->index = index_old; +        obj           = obj->next; +    } + +    buffer_copy(buffer, output, count); + +    return count; + +error_audio_stream_read:      return -1;  } @@ -47,13 +169,13 @@ xas_spatial_scene *xas_spatial_scene_new(xas_audio_format format,      scene->speaker_r = speaker_r;      scene->speed     = XAS_SPATIAL_DEFAULT_SPEED; -    if (buf_realloc(scene, NULL) < 0) { -        goto error_buf_realloc; +    if (buffer_realloc(scene, NULL) < 0) { +        goto error_buffer_realloc;      }      return scene; -error_buf_realloc: +error_buffer_realloc:      free(scene);  error_malloc_scene: @@ -61,19 +183,28 @@ error_malloc_scene:  }  void xas_spatial_scene_destroy(xas_spatial_scene *scene) { -    free(scene->buf); +    xas_spatial_object *object = scene->first; + +    while (object) { +        xas_spatial_object *next = object->next; + +        free(object); + +        object = next; +    } + +    free(scene->buffer);      free(scene);  } -int xas_spatial_scene_set_observer(xas_spatial_scene *scene, + +void xas_spatial_scene_set_observer(xas_spatial_scene *scene,                                        xas_spatial_coord coord,                                        xas_spatial_rotation rotation,                                        float width) {      scene->observer.coord    = coord;      scene->observer.rotation = rotation;      scene->observer.width    = width; - -    return buf_realloc(scene, scene->buf);  }  void xas_spatial_scene_set_speaker_coords(xas_spatial_scene *scene, @@ -83,6 +214,64 @@ void xas_spatial_scene_set_speaker_coords(xas_spatial_scene *scene,      scene->speaker_r = speaker_r;  } -void xas_spatial_scene_set_speed(xas_spatial_scene *scene, float speed) { +int xas_spatial_scene_set_speed(xas_spatial_scene *scene, float speed) {      scene->speed = speed; + +    return buffer_realloc(scene, scene->buffer); +} + +int xas_spatial_scene_set_radius(xas_spatial_scene *scene, float radius) { +    scene->radius = radius; + +    return buffer_realloc(scene, scene->buffer); +} + +xas_spatial_object *xas_spatial_scene_add_object(xas_spatial_scene *scene, +                                                     xas_spatial_coord coord, +                                                     xas_audio_stream *source) { +    xas_spatial_object *object; + +    if ((object = malloc(sizeof(*object))) == NULL) { +        goto error_malloc_object; +    } + +    object->coord  = coord; +    object->source = source; +    object->next   = NULL; + +    if (scene->first == NULL) { +        scene->first = object; +    } + +    if (scene->last) { +        scene->last->next = object; +    } + +    scene->last = object; + +    return object; + +error_malloc_object: +    return NULL; +} + +void xas_spatial_object_get_coord(xas_spatial_object *object, +                                    xas_spatial_coord *coord) { +    coord->x = object->coord.x; +    coord->y = object->coord.y; +    coord->z = object->coord.z; +} + +void xas_spatial_object_set_coord(xas_spatial_object *object, +                                    xas_spatial_coord coord) { +    object->coord = coord; +} + +xas_audio_stream *xas_spatial_scene_new_stream(xas_spatial_scene *scene, +                                                   size_t buffer_size) { +    return xas_audio_stream_new_source((xas_audio_fill)scene_fill, +                                         NULL, +                                         scene->format, +                                         buffer_size, +                                         scene);  } | 
 
    