src/audio/dc/SDL_dcaudio.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
permissions -rw-r--r--
more tweaking indent options
slouken@509
     1
/*
slouken@509
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@509
     4
slouken@509
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@509
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@509
     9
slouken@509
    10
    This library is distributed in the hope that it will be useful,
slouken@509
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@509
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@509
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@509
    18
slouken@1312
    19
    Sam Lantinga
slouken@1312
    20
    slouken@libsdl.org
slouken@509
    21
slouken@509
    22
*/
slouken@1402
    23
#include "SDL_config.h"
slouken@509
    24
slouken@509
    25
/* Output dreamcast aica */
slouken@509
    26
slouken@1358
    27
#include "SDL_timer.h"
slouken@509
    28
#include "SDL_audio.h"
slouken@1361
    29
#include "../SDL_audiomem.h"
slouken@1361
    30
#include "../SDL_audio_c.h"
slouken@1361
    31
#include "../SDL_audiodev_c.h"
slouken@509
    32
#include "SDL_dcaudio.h"
slouken@509
    33
slouken@509
    34
#include "aica.h"
slouken@509
    35
#include <dc/spu.h>
slouken@509
    36
slouken@509
    37
/* Audio driver functions */
slouken@1668
    38
static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
slouken@1668
    39
static void DCAUD_WaitAudio(_THIS);
slouken@1668
    40
static void DCAUD_PlayAudio(_THIS);
slouken@1668
    41
static Uint8 *DCAUD_GetAudioBuf(_THIS);
slouken@1668
    42
static void DCAUD_CloseAudio(_THIS);
slouken@509
    43
slouken@509
    44
/* Audio driver bootstrap functions */
slouken@1662
    45
static int
slouken@1668
    46
DCAUD_Available(void)
slouken@509
    47
{
slouken@1662
    48
    return 1;
slouken@509
    49
}
slouken@509
    50
slouken@1662
    51
static void
slouken@1668
    52
DCAUD_DeleteDevice(SDL_AudioDevice * device)
slouken@509
    53
{
slouken@1668
    54
    SDL_free(device->hidden);
slouken@1668
    55
    SDL_free(device);
slouken@509
    56
}
slouken@509
    57
slouken@1662
    58
static SDL_AudioDevice *
slouken@1668
    59
DCAUD_CreateDevice(int devindex)
slouken@509
    60
{
slouken@1662
    61
    SDL_AudioDevice *this;
slouken@509
    62
slouken@1662
    63
    /* Initialize all variables that we clean on shutdown */
slouken@1668
    64
    this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
slouken@1662
    65
    if (this) {
slouken@1668
    66
        SDL_memset(this, 0, (sizeof *this));
slouken@1662
    67
        this->hidden = (struct SDL_PrivateAudioData *)
slouken@1668
    68
            SDL_malloc((sizeof *this->hidden));
slouken@1662
    69
    }
slouken@1662
    70
    if ((this == NULL) || (this->hidden == NULL)) {
slouken@1668
    71
        SDL_OutOfMemory();
slouken@1662
    72
        if (this) {
slouken@1668
    73
            SDL_free(this);
slouken@1662
    74
        }
slouken@1662
    75
        return (0);
slouken@1662
    76
    }
slouken@1668
    77
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
slouken@509
    78
slouken@1662
    79
    /* Set the function pointers */
slouken@1662
    80
    this->OpenAudio = DCAUD_OpenAudio;
slouken@1662
    81
    this->WaitAudio = DCAUD_WaitAudio;
slouken@1662
    82
    this->PlayAudio = DCAUD_PlayAudio;
slouken@1662
    83
    this->GetAudioBuf = DCAUD_GetAudioBuf;
slouken@1662
    84
    this->CloseAudio = DCAUD_CloseAudio;
slouken@509
    85
slouken@1662
    86
    this->free = DCAUD_DeleteDevice;
slouken@509
    87
slouken@1668
    88
    spu_init();
slouken@509
    89
slouken@1662
    90
    return this;
slouken@509
    91
}
slouken@509
    92
slouken@509
    93
AudioBootStrap DCAUD_bootstrap = {
slouken@1662
    94
    "dcaudio", "Dreamcast AICA audio",
slouken@1662
    95
    DCAUD_Available, DCAUD_CreateDevice
slouken@509
    96
};
slouken@509
    97
slouken@509
    98
/* This function waits until it is possible to write a full sound buffer */
slouken@1662
    99
static void
slouken@1668
   100
DCAUD_WaitAudio(_THIS)
slouken@509
   101
{
slouken@1662
   102
    if (this->hidden->playing) {
slouken@1662
   103
        /* wait */
slouken@1668
   104
        while (aica_get_pos(0) / this->spec.samples == this->hidden->nextbuf) {
slouken@1668
   105
            thd_pass();
slouken@1662
   106
        }
slouken@1662
   107
    }
slouken@509
   108
}
slouken@509
   109
slouken@509
   110
#define	SPU_RAM_BASE	0xa0800000
slouken@509
   111
slouken@1662
   112
static void
slouken@1668
   113
spu_memload_stereo8(int leftpos, int rightpos, void *src0, size_t size)
slouken@509
   114
{
slouken@1662
   115
    uint8 *src = src0;
slouken@1662
   116
    uint32 *left = (uint32 *) (leftpos + SPU_RAM_BASE);
slouken@1662
   117
    uint32 *right = (uint32 *) (rightpos + SPU_RAM_BASE);
slouken@1662
   118
    size = (size + 7) / 8;
slouken@1662
   119
    while (size--) {
slouken@1662
   120
        unsigned lval, rval;
slouken@1662
   121
        lval = *src++;
slouken@1662
   122
        rval = *src++;
slouken@1662
   123
        lval |= (*src++) << 8;
slouken@1662
   124
        rval |= (*src++) << 8;
slouken@1662
   125
        lval |= (*src++) << 16;
slouken@1662
   126
        rval |= (*src++) << 16;
slouken@1662
   127
        lval |= (*src++) << 24;
slouken@1662
   128
        rval |= (*src++) << 24;
slouken@1668
   129
        g2_write_32(left++, lval);
slouken@1668
   130
        g2_write_32(right++, rval);
slouken@1668
   131
        g2_fifo_wait();
slouken@1662
   132
    }
slouken@509
   133
}
slouken@509
   134
slouken@1662
   135
static void
slouken@1668
   136
spu_memload_stereo16(int leftpos, int rightpos, void *src0, size_t size)
slouken@509
   137
{
slouken@1662
   138
    uint16 *src = src0;
slouken@1662
   139
    uint32 *left = (uint32 *) (leftpos + SPU_RAM_BASE);
slouken@1662
   140
    uint32 *right = (uint32 *) (rightpos + SPU_RAM_BASE);
slouken@1662
   141
    size = (size + 7) / 8;
slouken@1662
   142
    while (size--) {
slouken@1662
   143
        unsigned lval, rval;
slouken@1662
   144
        lval = *src++;
slouken@1662
   145
        rval = *src++;
slouken@1662
   146
        lval |= (*src++) << 16;
slouken@1662
   147
        rval |= (*src++) << 16;
slouken@1668
   148
        g2_write_32(left++, lval);
slouken@1668
   149
        g2_write_32(right++, rval);
slouken@1668
   150
        g2_fifo_wait();
slouken@1662
   151
    }
slouken@509
   152
}
slouken@509
   153
slouken@1662
   154
static void
slouken@1668
   155
DCAUD_PlayAudio(_THIS)
slouken@509
   156
{
slouken@1662
   157
    SDL_AudioSpec *spec = &this->spec;
slouken@1662
   158
    unsigned int offset;
slouken@509
   159
slouken@1662
   160
    if (this->hidden->playing) {
slouken@1662
   161
        /* wait */
slouken@1668
   162
        while (aica_get_pos(0) / spec->samples == this->hidden->nextbuf) {
slouken@1668
   163
            thd_pass();
slouken@1662
   164
        }
slouken@1662
   165
    }
slouken@509
   166
slouken@1662
   167
    offset = this->hidden->nextbuf * spec->size;
slouken@1662
   168
    this->hidden->nextbuf ^= 1;
slouken@1662
   169
    /* Write the audio data, checking for EAGAIN on broken audio drivers */
slouken@1662
   170
    if (spec->channels == 1) {
slouken@1668
   171
        spu_memload(this->hidden->leftpos + offset, this->hidden->mixbuf,
slouken@1668
   172
                    this->hidden->mixlen);
slouken@1662
   173
    } else {
slouken@1662
   174
        offset /= 2;
slouken@1662
   175
        if ((this->spec.format & 255) == 8) {
slouken@1668
   176
            spu_memload_stereo8(this->hidden->leftpos + offset,
slouken@1668
   177
                                this->hidden->rightpos + offset,
slouken@1668
   178
                                this->hidden->mixbuf, this->hidden->mixlen);
slouken@1668
   179
        } else {
slouken@1668
   180
            spu_memload_stereo16(this->hidden->leftpos + offset,
slouken@1662
   181
                                 this->hidden->rightpos + offset,
slouken@1662
   182
                                 this->hidden->mixbuf, this->hidden->mixlen);
slouken@1662
   183
        }
slouken@1662
   184
    }
slouken@509
   185
slouken@1662
   186
    if (!this->hidden->playing) {
slouken@1662
   187
        int mode;
slouken@1662
   188
        this->hidden->playing = 1;
slouken@1662
   189
        mode = (spec->format == AUDIO_S8) ? SM_8BIT : SM_16BIT;
slouken@1662
   190
        if (spec->channels == 1) {
slouken@1668
   191
            aica_play(0, mode, this->hidden->leftpos, 0,
slouken@1668
   192
                      spec->samples * 2, spec->freq, 255, 128, 1);
slouken@1662
   193
        } else {
slouken@1668
   194
            aica_play(0, mode, this->hidden->leftpos, 0,
slouken@1668
   195
                      spec->samples * 2, spec->freq, 255, 0, 1);
slouken@1668
   196
            aica_play(1, mode, this->hidden->rightpos, 0,
slouken@1668
   197
                      spec->samples * 2, spec->freq, 255, 255, 1);
slouken@1662
   198
        }
slouken@1662
   199
    }
slouken@509
   200
}
slouken@509
   201
slouken@1662
   202
static Uint8 *
slouken@1668
   203
DCAUD_GetAudioBuf(_THIS)
slouken@509
   204
{
slouken@1662
   205
    return (this->hidden->mixbuf);
slouken@509
   206
}
slouken@509
   207
slouken@1662
   208
static void
slouken@1668
   209
DCAUD_CloseAudio(_THIS)
slouken@509
   210
{
slouken@1668
   211
    aica_stop(0);
slouken@1662
   212
    if (this->spec.channels == 2)
slouken@1668
   213
        aica_stop(1);
slouken@1662
   214
    if (this->hidden->mixbuf != NULL) {
slouken@1668
   215
        SDL_FreeAudioMem(this->hidden->mixbuf);
slouken@1662
   216
        this->hidden->mixbuf = NULL;
slouken@1662
   217
    }
slouken@509
   218
}
slouken@509
   219
slouken@1662
   220
static int
slouken@1668
   221
DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
slouken@509
   222
{
slouken@1662
   223
    switch (spec->format & 0xff) {
slouken@1662
   224
    case 8:
slouken@1662
   225
        spec->format = AUDIO_S8;
slouken@1662
   226
        break;
slouken@1662
   227
    case 16:
slouken@1662
   228
        spec->format = AUDIO_S16LSB;
slouken@1662
   229
        break;
slouken@1662
   230
    default:
slouken@1668
   231
        SDL_SetError("Unsupported audio format");
slouken@1662
   232
        return (-1);
slouken@1662
   233
    }
slouken@509
   234
slouken@1662
   235
    /* Update the fragment size as size in bytes */
slouken@1668
   236
    SDL_CalculateAudioSpec(spec);
slouken@509
   237
slouken@1662
   238
    /* Allocate mixing buffer */
slouken@1662
   239
    this->hidden->mixlen = spec->size;
slouken@1668
   240
    this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
slouken@1662
   241
    if (this->hidden->mixbuf == NULL) {
slouken@1662
   242
        return (-1);
slouken@1662
   243
    }
slouken@1668
   244
    SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
slouken@1662
   245
    this->hidden->leftpos = 0x11000;
slouken@1662
   246
    this->hidden->rightpos = 0x11000 + spec->size;
slouken@1662
   247
    this->hidden->playing = 0;
slouken@1662
   248
    this->hidden->nextbuf = 0;
slouken@509
   249
slouken@1662
   250
    /* We're ready to rock and roll. :-) */
slouken@1662
   251
    return (0);
slouken@509
   252
}
slouken@1662
   253
slouken@1662
   254
/* vi: set ts=4 sw=4 expandtab: */