cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_fsaudio.c (9254B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../../SDL_internal.h"
     22
     23#if SDL_AUDIO_DRIVER_FUSIONSOUND
     24
     25/* Allow access to a raw mixing buffer */
     26
     27#ifdef HAVE_SIGNAL_H
     28#include <signal.h>
     29#endif
     30#include <unistd.h>
     31
     32#include "SDL_timer.h"
     33#include "SDL_audio.h"
     34#include "../SDL_audiomem.h"
     35#include "../SDL_audio_c.h"
     36#include "SDL_fsaudio.h"
     37
     38#include <fusionsound/fusionsound_version.h>
     39
     40/* #define SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC "libfusionsound.so" */
     41
     42#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
     43#include "SDL_name.h"
     44#include "SDL_loadso.h"
     45#else
     46#define SDL_NAME(X) X
     47#endif
     48
     49#if (FUSIONSOUND_MAJOR_VERSION == 1) && (FUSIONSOUND_MINOR_VERSION < 1)
     50typedef DFBResult DirectResult;
     51#endif
     52
     53/* Buffers to use - more than 2 gives a lot of latency */
     54#define FUSION_BUFFERS              (2)
     55
     56#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
     57
     58static const char *fs_library = SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC;
     59static void *fs_handle = NULL;
     60
     61static DirectResult (*SDL_NAME(FusionSoundInit)) (int *argc, char *(*argv[]));
     62static DirectResult (*SDL_NAME(FusionSoundCreate)) (IFusionSound **
     63                                                   ret_interface);
     64
     65#define SDL_FS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
     66static struct
     67{
     68    const char *name;
     69    void **func;
     70} fs_functions[] = {
     71/* *INDENT-OFF* */
     72    SDL_FS_SYM(FusionSoundInit),
     73    SDL_FS_SYM(FusionSoundCreate),
     74/* *INDENT-ON* */
     75};
     76
     77#undef SDL_FS_SYM
     78
     79static void
     80UnloadFusionSoundLibrary()
     81{
     82    if (fs_handle != NULL) {
     83        SDL_UnloadObject(fs_handle);
     84        fs_handle = NULL;
     85    }
     86}
     87
     88static int
     89LoadFusionSoundLibrary(void)
     90{
     91    int i, retval = -1;
     92
     93    if (fs_handle == NULL) {
     94        fs_handle = SDL_LoadObject(fs_library);
     95        if (fs_handle != NULL) {
     96            retval = 0;
     97            for (i = 0; i < SDL_arraysize(fs_functions); ++i) {
     98                *fs_functions[i].func =
     99                    SDL_LoadFunction(fs_handle, fs_functions[i].name);
    100                if (!*fs_functions[i].func) {
    101                    retval = -1;
    102                    UnloadFusionSoundLibrary();
    103                    break;
    104                }
    105            }
    106        }
    107    }
    108
    109    return retval;
    110}
    111
    112#else
    113
    114static void
    115UnloadFusionSoundLibrary()
    116{
    117    return;
    118}
    119
    120static int
    121LoadFusionSoundLibrary(void)
    122{
    123    return 0;
    124}
    125
    126#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC */
    127
    128/* This function waits until it is possible to write a full sound buffer */
    129static void
    130SDL_FS_WaitDevice(_THIS)
    131{
    132    this->hidden->stream->Wait(this->hidden->stream,
    133                               this->hidden->mixsamples);
    134}
    135
    136static void
    137SDL_FS_PlayDevice(_THIS)
    138{
    139    DirectResult ret;
    140
    141    ret = this->hidden->stream->Write(this->hidden->stream,
    142                                      this->hidden->mixbuf,
    143                                      this->hidden->mixsamples);
    144    /* If we couldn't write, assume fatal error for now */
    145    if (ret) {
    146        this->enabled = 0;
    147    }
    148#ifdef DEBUG_AUDIO
    149    fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
    150#endif
    151}
    152
    153static void
    154SDL_FS_WaitDone(_THIS)
    155{
    156    this->hidden->stream->Wait(this->hidden->stream,
    157                               this->hidden->mixsamples * FUSION_BUFFERS);
    158}
    159
    160
    161static Uint8 *
    162SDL_FS_GetDeviceBuf(_THIS)
    163{
    164    return (this->hidden->mixbuf);
    165}
    166
    167
    168static void
    169SDL_FS_CloseDevice(_THIS)
    170{
    171    if (this->hidden != NULL) {
    172        SDL_FreeAudioMem(this->hidden->mixbuf);
    173        this->hidden->mixbuf = NULL;
    174        if (this->hidden->stream) {
    175            this->hidden->stream->Release(this->hidden->stream);
    176            this->hidden->stream = NULL;
    177        }
    178        if (this->hidden->fs) {
    179            this->hidden->fs->Release(this->hidden->fs);
    180            this->hidden->fs = NULL;
    181        }
    182        SDL_free(this->hidden);
    183        this->hidden = NULL;
    184    }
    185}
    186
    187
    188static int
    189SDL_FS_OpenDevice(_THIS, const char *devname, int iscapture)
    190{
    191    int bytes;
    192    SDL_AudioFormat test_format = 0, format = 0;
    193    FSSampleFormat fs_format;
    194    FSStreamDescription desc;
    195    DirectResult ret;
    196
    197    /* Initialize all variables that we clean on shutdown */
    198    this->hidden = (struct SDL_PrivateAudioData *)
    199        SDL_malloc((sizeof *this->hidden));
    200    if (this->hidden == NULL) {
    201        return SDL_OutOfMemory();
    202    }
    203    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
    204
    205    /* Try for a closest match on audio format */
    206    for (test_format = SDL_FirstAudioFormat(this->spec.format);
    207         !format && test_format;) {
    208#ifdef DEBUG_AUDIO
    209        fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
    210#endif
    211        switch (test_format) {
    212        case AUDIO_U8:
    213            fs_format = FSSF_U8;
    214            bytes = 1;
    215            format = 1;
    216            break;
    217        case AUDIO_S16SYS:
    218            fs_format = FSSF_S16;
    219            bytes = 2;
    220            format = 1;
    221            break;
    222        case AUDIO_S32SYS:
    223            fs_format = FSSF_S32;
    224            bytes = 4;
    225            format = 1;
    226            break;
    227        case AUDIO_F32SYS:
    228            fs_format = FSSF_FLOAT;
    229            bytes = 4;
    230            format = 1;
    231            break;
    232        default:
    233            format = 0;
    234            break;
    235        }
    236        if (!format) {
    237            test_format = SDL_NextAudioFormat();
    238        }
    239    }
    240
    241    if (format == 0) {
    242        SDL_FS_CloseDevice(this);
    243        return SDL_SetError("Couldn't find any hardware audio formats");
    244    }
    245    this->spec.format = test_format;
    246
    247    /* Retrieve the main sound interface. */
    248    ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
    249    if (ret) {
    250        SDL_FS_CloseDevice(this);
    251        return SDL_SetError("Unable to initialize FusionSound: %d", ret);
    252    }
    253
    254    this->hidden->mixsamples = this->spec.size / bytes / this->spec.channels;
    255
    256    /* Fill stream description. */
    257    desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
    258        FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT | FSSDF_PREBUFFER;
    259    desc.samplerate = this->spec.freq;
    260    desc.buffersize = this->spec.size * FUSION_BUFFERS;
    261    desc.channels = this->spec.channels;
    262    desc.prebuffer = 10;
    263    desc.sampleformat = fs_format;
    264
    265    ret =
    266        this->hidden->fs->CreateStream(this->hidden->fs, &desc,
    267                                       &this->hidden->stream);
    268    if (ret) {
    269        SDL_FS_CloseDevice(this);
    270        return SDL_SetError("Unable to create FusionSoundStream: %d", ret);
    271    }
    272
    273    /* See what we got */
    274    desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
    275        FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT;
    276    ret = this->hidden->stream->GetDescription(this->hidden->stream, &desc);
    277
    278    this->spec.freq = desc.samplerate;
    279    this->spec.size =
    280        desc.buffersize / FUSION_BUFFERS * bytes * desc.channels;
    281    this->spec.channels = desc.channels;
    282
    283    /* Calculate the final parameters for this audio specification */
    284    SDL_CalculateAudioSpec(&this->spec);
    285
    286    /* Allocate mixing buffer */
    287    this->hidden->mixlen = this->spec.size;
    288    this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
    289    if (this->hidden->mixbuf == NULL) {
    290        SDL_FS_CloseDevice(this);
    291        return SDL_OutOfMemory();
    292    }
    293    SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
    294
    295    /* We're ready to rock and roll. :-) */
    296    return 0;
    297}
    298
    299
    300static void
    301SDL_FS_Deinitialize(void)
    302{
    303    UnloadFusionSoundLibrary();
    304}
    305
    306
    307static int
    308SDL_FS_Init(SDL_AudioDriverImpl * impl)
    309{
    310    if (LoadFusionSoundLibrary() < 0) {
    311        return 0;
    312    } else {
    313        DirectResult ret;
    314
    315        ret = SDL_NAME(FusionSoundInit) (NULL, NULL);
    316        if (ret) {
    317            UnloadFusionSoundLibrary();
    318            SDL_SetError
    319                ("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)",
    320                 ret);
    321            return 0;
    322        }
    323    }
    324
    325    /* Set the function pointers */
    326    impl->OpenDevice = SDL_FS_OpenDevice;
    327    impl->PlayDevice = SDL_FS_PlayDevice;
    328    impl->WaitDevice = SDL_FS_WaitDevice;
    329    impl->GetDeviceBuf = SDL_FS_GetDeviceBuf;
    330    impl->CloseDevice = SDL_FS_CloseDevice;
    331    impl->WaitDone = SDL_FS_WaitDone;
    332    impl->Deinitialize = SDL_FS_Deinitialize;
    333    impl->OnlyHasDefaultOutputDevice = 1;
    334
    335    return 1;   /* this audio target is available. */
    336}
    337
    338
    339AudioBootStrap FUSIONSOUND_bootstrap = {
    340    "fusionsound", "FusionSound", SDL_FS_Init, 0
    341};
    342
    343#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND */
    344
    345/* vi: set ts=4 sw=4 expandtab: */