src/audio/disk/SDL_diskaudio.c
author Ryan C. Gordon
Wed, 18 Jan 2017 02:11:56 -0500
changeset 10817 efc103e60c5b
parent 10755 43953bdaa3ee
child 11811 5d94cb6b24d3
permissions -rw-r--r--
audio: Several fixes to "simple" resampler (thanks, Vitaly!).

Fixes Bugzilla #3551.
slouken@68
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@68
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@68
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@68
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@68
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@68
    22
slouken@6044
    23
#if SDL_AUDIO_DRIVER_DISK
slouken@6044
    24
slouken@68
    25
/* Output raw audio data to a file. */
slouken@68
    26
slouken@1465
    27
#if HAVE_STDIO_H
slouken@68
    28
#include <stdio.h>
slouken@1465
    29
#endif
slouken@68
    30
slouken@1465
    31
#include "SDL_rwops.h"
slouken@1358
    32
#include "SDL_timer.h"
slouken@68
    33
#include "SDL_audio.h"
slouken@1361
    34
#include "../SDL_audio_c.h"
slouken@68
    35
#include "SDL_diskaudio.h"
icculus@10755
    36
#include "SDL_log.h"
slouken@68
    37
icculus@10264
    38
/* !!! FIXME: these should be SDL hints, not environment variables. */
slouken@68
    39
/* environment variables and defaults. */
slouken@68
    40
#define DISKENVR_OUTFILE         "SDL_DISKAUDIOFILE"
slouken@68
    41
#define DISKDEFAULT_OUTFILE      "sdlaudio.raw"
icculus@10264
    42
#define DISKENVR_INFILE         "SDL_DISKAUDIOFILEIN"
icculus@10264
    43
#define DISKDEFAULT_INFILE      "sdlaudio-in.raw"
icculus@10264
    44
#define DISKENVR_IODELAY      "SDL_DISKAUDIODELAY"
slouken@68
    45
slouken@68
    46
/* This function waits until it is possible to write a full sound buffer */
slouken@1895
    47
static void
icculus@10281
    48
DISKAUDIO_WaitDevice(_THIS)
slouken@68
    49
{
icculus@10264
    50
    SDL_Delay(this->hidden->io_delay);
slouken@68
    51
}
slouken@68
    52
slouken@1895
    53
static void
icculus@10281
    54
DISKAUDIO_PlayDevice(_THIS)
slouken@68
    55
{
icculus@10264
    56
    const size_t written = SDL_RWwrite(this->hidden->io,
icculus@10264
    57
                                       this->hidden->mixbuf,
icculus@10264
    58
                                       1, this->spec.size);
slouken@68
    59
slouken@1895
    60
    /* If we couldn't write, assume fatal error for now */
icculus@10264
    61
    if (written != this->spec.size) {
icculus@9394
    62
        SDL_OpenedAudioDeviceDisconnected(this);
slouken@1895
    63
    }
slouken@68
    64
#ifdef DEBUG_AUDIO
slouken@1895
    65
    fprintf(stderr, "Wrote %d bytes of audio data\n", written);
slouken@68
    66
#endif
slouken@68
    67
}
slouken@68
    68
slouken@1895
    69
static Uint8 *
icculus@10281
    70
DISKAUDIO_GetDeviceBuf(_THIS)
slouken@68
    71
{
slouken@1895
    72
    return (this->hidden->mixbuf);
slouken@68
    73
}
slouken@68
    74
icculus@10264
    75
static int
icculus@10281
    76
DISKAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
icculus@10264
    77
{
icculus@10264
    78
    struct SDL_PrivateAudioData *h = this->hidden;
icculus@10264
    79
    const int origbuflen = buflen;
icculus@10264
    80
icculus@10264
    81
    SDL_Delay(h->io_delay);
icculus@10264
    82
icculus@10264
    83
    if (h->io) {
icculus@10264
    84
        const size_t br = SDL_RWread(h->io, buffer, 1, buflen);
icculus@10264
    85
        buflen -= (int) br;
icculus@10264
    86
        buffer = ((Uint8 *) buffer) + br;
icculus@10264
    87
        if (buflen > 0) {  /* EOF (or error, but whatever). */
icculus@10264
    88
            SDL_RWclose(h->io);
icculus@10264
    89
            h->io = NULL;
icculus@10264
    90
        }
icculus@10264
    91
    }
icculus@10264
    92
icculus@10264
    93
    /* if we ran out of file, just write silence. */
icculus@10264
    94
    SDL_memset(buffer, this->spec.silence, buflen);
icculus@10264
    95
icculus@10264
    96
    return origbuflen;
icculus@10264
    97
}
icculus@10264
    98
icculus@10264
    99
static void
icculus@10281
   100
DISKAUDIO_FlushCapture(_THIS)
icculus@10264
   101
{
icculus@10264
   102
    /* no op...we don't advance the file pointer or anything. */
icculus@10264
   103
}
icculus@10264
   104
icculus@10264
   105
slouken@1895
   106
static void
icculus@10281
   107
DISKAUDIO_CloseDevice(_THIS)
slouken@68
   108
{
icculus@10264
   109
    if (this->hidden->io != NULL) {
icculus@10264
   110
        SDL_RWclose(this->hidden->io);
slouken@1895
   111
    }
icculus@10256
   112
    SDL_free(this->hidden->mixbuf);
icculus@10255
   113
    SDL_free(this->hidden);
slouken@68
   114
}
slouken@68
   115
icculus@10264
   116
icculus@10264
   117
static const char *
icculus@10264
   118
get_filename(const int iscapture, const char *devname)
icculus@10264
   119
{
icculus@10264
   120
    if (devname == NULL) {
icculus@10264
   121
        devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
icculus@10264
   122
        if (devname == NULL) {
icculus@10264
   123
            devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
icculus@10264
   124
        }
icculus@10264
   125
    }
icculus@10264
   126
    return devname;
icculus@10264
   127
}
icculus@10264
   128
slouken@1895
   129
static int
icculus@10281
   130
DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
slouken@68
   131
{
icculus@9786
   132
    /* handle != NULL means "user specified the placeholder name on the fake detected device list" */
icculus@10264
   133
    const char *fname = get_filename(iscapture, handle ? NULL : devname);
icculus@10264
   134
    const char *envr = SDL_getenv(DISKENVR_IODELAY);
icculus@2049
   135
icculus@2049
   136
    this->hidden = (struct SDL_PrivateAudioData *)
slouken@2060
   137
        SDL_malloc(sizeof(*this->hidden));
icculus@2049
   138
    if (this->hidden == NULL) {
icculus@7038
   139
        return SDL_OutOfMemory();
icculus@2049
   140
    }
icculus@10257
   141
    SDL_zerop(this->hidden);
slouken@68
   142
icculus@10265
   143
    if (envr != NULL) {
icculus@10265
   144
        this->hidden->io_delay = SDL_atoi(envr);
icculus@10265
   145
    } else {
icculus@10265
   146
        this->hidden->io_delay = ((this->spec.samples * 1000) / this->spec.freq);
icculus@10265
   147
    }
icculus@7366
   148
slouken@1895
   149
    /* Open the audio device */
icculus@10264
   150
    this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
icculus@10264
   151
    if (this->hidden->io == NULL) {
icculus@7038
   152
        return -1;
slouken@1895
   153
    }
slouken@68
   154
slouken@1895
   155
    /* Allocate mixing buffer */
icculus@10264
   156
    if (!iscapture) {
icculus@10264
   157
        this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
icculus@10264
   158
        if (this->hidden->mixbuf == NULL) {
icculus@10264
   159
            return SDL_OutOfMemory();
icculus@10264
   160
        }
icculus@10264
   161
        SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
slouken@1895
   162
    }
icculus@2049
   163
icculus@10755
   164
    SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO,
icculus@10755
   165
                "You are using the SDL disk i/o audio driver!\n");
icculus@10755
   166
    SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO,
icculus@10755
   167
                " %s file [%s].\n", iscapture ? "Reading from" : "Writing to",
icculus@10755
   168
                fname);
slouken@68
   169
slouken@1895
   170
    /* We're ready to rock and roll. :-) */
icculus@7038
   171
    return 0;
slouken@68
   172
}
slouken@68
   173
icculus@9786
   174
static void
icculus@10281
   175
DISKAUDIO_DetectDevices(void)
icculus@9786
   176
{
icculus@10264
   177
    SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1);
icculus@10264
   178
    SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2);
icculus@9786
   179
}
icculus@9786
   180
icculus@2049
   181
static int
icculus@10281
   182
DISKAUDIO_Init(SDL_AudioDriverImpl * impl)
icculus@2049
   183
{
icculus@2049
   184
    /* Set the function pointers */
icculus@10281
   185
    impl->OpenDevice = DISKAUDIO_OpenDevice;
icculus@10281
   186
    impl->WaitDevice = DISKAUDIO_WaitDevice;
icculus@10281
   187
    impl->PlayDevice = DISKAUDIO_PlayDevice;
icculus@10281
   188
    impl->GetDeviceBuf = DISKAUDIO_GetDeviceBuf;
icculus@10281
   189
    impl->CaptureFromDevice = DISKAUDIO_CaptureFromDevice;
icculus@10281
   190
    impl->FlushCapture = DISKAUDIO_FlushCapture;
icculus@10264
   191
icculus@10281
   192
    impl->CloseDevice = DISKAUDIO_CloseDevice;
icculus@10281
   193
    impl->DetectDevices = DISKAUDIO_DetectDevices;
icculus@2049
   194
icculus@9394
   195
    impl->AllowsArbitraryDeviceNames = 1;
icculus@10264
   196
    impl->HasCaptureSupport = SDL_TRUE;
icculus@9394
   197
icculus@3699
   198
    return 1;   /* this audio target is available. */
icculus@2049
   199
}
icculus@2049
   200
icculus@10281
   201
AudioBootStrap DISKAUDIO_bootstrap = {
icculus@10281
   202
    "disk", "direct-to-disk audio", DISKAUDIO_Init, 1
icculus@2049
   203
};
icculus@2049
   204
slouken@6044
   205
#endif /* SDL_AUDIO_DRIVER_DISK */
slouken@6044
   206
slouken@1895
   207
/* vi: set ts=4 sw=4 expandtab: */