Subversion Repositories eduke32

Rev

Rev 4541 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1471 terminx 1
/*
2
 Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
3
 
4
 This program is free software; you can redistribute it and/or
5
 modify it under the terms of the GNU General Public License
6
 as published by the Free Software Foundation; either version 2
7
 of the License, or (at your option) any later version.
8
 
9
 This program is distributed in the hope that it will be useful,
10
 but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
 
13
 See the GNU General Public License for more details.
14
 
15
 You should have received a copy of the GNU General Public License
16
 along with this program; if not, write to the Free Software
4541 hendricks2 17
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
1471 terminx 18
 
19
 */
20
 
21
/**
22
 * libSDL output driver for MultiVoc
23
 */
24
 
4074 hendricks2 25
#include <string.h>
26
#define _NEED_SDLMIXER
4997 terminx 27
#include "compat.h"
4074 hendricks2 28
#include "sdl_inc.h"
1471 terminx 29
#include "driver_sdl.h"
3338 hendricks2 30
#include "multivoc.h"
1471 terminx 31
 
4440 terminx 32
#ifdef __ANDROID__
33
#include "duke3d.h"
34
#include "android.h"
35
#endif
36
 
1471 terminx 37
enum {
38
   SDLErr_Warning = -2,
39
   SDLErr_Error   = -1,
40
   SDLErr_Ok      = 0,
41
   SDLErr_Uninitialised,
42
   SDLErr_InitSubSystem,
43
   SDLErr_OpenAudio
44
};
45
 
46
static int32_t ErrorCode = SDLErr_Ok;
47
static int32_t Initialised = 0;
48
static int32_t Playing = 0;
1481 terminx 49
// static int32_t StartedSDL = -1;
1471 terminx 50
 
51
static char *MixBuffer = 0;
52
static int32_t MixBufferSize = 0;
53
static int32_t MixBufferCount = 0;
54
static int32_t MixBufferCurrent = 0;
55
static int32_t MixBufferUsed = 0;
56
static void ( *MixCallBack )( void ) = 0;
57
 
1473 terminx 58
static Mix_Chunk *DummyChunk = NULL;
59
static uint8_t *DummyBuffer = NULL;
1583 plagman 60
static int32_t InterruptsDisabled = 0;
61
static SDL_mutex *EffectFence;
1473 terminx 62
 
63
static void fillData(int32_t chan, void *ptr, int32_t remaining, void *udata)
1471 terminx 64
{
65
        int32_t len;
66
        char *sptr;
67
 
1473 terminx 68
    UNREFERENCED_PARAMETER(chan);
69
    UNREFERENCED_PARAMETER(udata);
1585 plagman 70
 
71
    if (!MixBuffer || !MixCallBack)
72
      return;
1473 terminx 73
 
1583 plagman 74
    SDL_LockMutex(EffectFence);
75
 
1471 terminx 76
        while (remaining > 0) {
77
                if (MixBufferUsed == MixBufferSize) {
78
                        MixCallBack();
79
 
80
                        MixBufferUsed = 0;
81
                        MixBufferCurrent++;
82
                        if (MixBufferCurrent >= MixBufferCount) {
83
                                MixBufferCurrent -= MixBufferCount;
84
                        }
85
                }
86
 
87
                while (remaining > 0 && MixBufferUsed < MixBufferSize) {
88
                        sptr = MixBuffer + (MixBufferCurrent * MixBufferSize) + MixBufferUsed;
89
 
90
                        len = MixBufferSize - MixBufferUsed;
91
                        if (remaining < len) {
92
                                len = remaining;
93
                        }
94
 
95
                        memcpy(ptr, sptr, len);
96
 
3140 Plagman 97
                        ptr = (void *)((uintptr_t)(ptr) + len);
1471 terminx 98
                        MixBufferUsed += len;
99
                        remaining -= len;
100
                }
101
        }
1583 plagman 102
 
103
    SDL_UnlockMutex(EffectFence);
1471 terminx 104
}
105
 
106
 
107
int32_t SDLDrv_GetError(void)
108
{
109
    return ErrorCode;
110
}
111
 
112
const char *SDLDrv_ErrorString( int32_t ErrorNumber )
113
{
114
    const char *ErrorString;
115
 
116
    switch( ErrorNumber ) {
117
        case SDLErr_Warning :
118
        case SDLErr_Error :
119
            ErrorString = SDLDrv_ErrorString( ErrorCode );
120
            break;
121
 
122
        case SDLErr_Ok :
123
            ErrorString = "SDL Audio ok.";
124
            break;
125
 
126
        case SDLErr_Uninitialised:
127
            ErrorString = "SDL Audio uninitialised.";
128
            break;
129
 
130
        case SDLErr_InitSubSystem:
131
            ErrorString = "SDL Audio: error in Init or InitSubSystem.";
132
            break;
133
 
134
        case SDLErr_OpenAudio:
135
            ErrorString = "SDL Audio: error in OpenAudio.";
136
            break;
137
 
138
        default:
139
            ErrorString = "Unknown SDL Audio error code.";
140
            break;
141
    }
142
 
143
    return ErrorString;
144
}
145
 
1481 terminx 146
int32_t SDLDrv_PCM_Init(int32_t *mixrate, int32_t *numchannels, int32_t *samplebits, void * initdata)
1471 terminx 147
{
1473 terminx 148
    int32_t err = 0;
1474 terminx 149
    int32_t chunksize;
1481 terminx 150
    uint16_t fmt;
1471 terminx 151
 
1474 terminx 152
    UNREFERENCED_PARAMETER(numchannels);
1473 terminx 153
    UNREFERENCED_PARAMETER(initdata);
154
 
1471 terminx 155
    if (Initialised) {
1481 terminx 156
        SDLDrv_PCM_Shutdown();
1471 terminx 157
    }
158
 
1474 terminx 159
    chunksize = 512;
4440 terminx 160
#ifdef __ANDROID__
161
    chunksize = droidinfo.audio_buffer_size;
162
#endif
1585 plagman 163
 
164
    if (*mixrate >= 16000) chunksize *= 2;
1481 terminx 165
    if (*mixrate >= 32000) chunksize *= 2;
1471 terminx 166
 
1487 terminx 167
    err = Mix_OpenAudio(*mixrate, (*samplebits == 8) ? AUDIO_U8 : AUDIO_S16SYS, *numchannels, chunksize);
1473 terminx 168
 
1471 terminx 169
    if (err < 0) {
170
        ErrorCode = SDLErr_OpenAudio;
171
        return SDLErr_Error;
172
    }
173
 
1487 terminx 174
    if (Mix_QuerySpec(mixrate, &fmt, numchannels))
175
    {
176
        if (fmt == AUDIO_U8 || fmt == AUDIO_S8) *samplebits = 8;
177
        else *samplebits = 16;
178
    }
1481 terminx 179
 
1473 terminx 180
    //Mix_SetPostMix(fillData, NULL);
181
 
1583 plagman 182
    EffectFence = SDL_CreateMutex();
183
 
1473 terminx 184
    // channel 0 and 1 are actual sounds
185
    // dummy channel 2 runs our fillData() callback as an effect
186
    Mix_RegisterEffect(2, fillData, NULL, NULL);
187
 
1474 terminx 188
    DummyBuffer = (uint8_t *) malloc(chunksize);
189
    memset(DummyBuffer, 0, chunksize);
1473 terminx 190
 
1474 terminx 191
    DummyChunk = Mix_QuickLoad_RAW(DummyBuffer, chunksize);
1473 terminx 192
 
193
    Mix_PlayChannel(2, DummyChunk, -1);
194
 
1471 terminx 195
    Initialised = 1;
196
 
197
    return SDLErr_Ok;
198
}
199
 
1481 terminx 200
void SDLDrv_PCM_Shutdown(void)
1471 terminx 201
{
1487 terminx 202
    if (!Initialised)
1471 terminx 203
        return;
1487 terminx 204
    else Mix_HaltChannel(-1);
205
 
206
    if (DummyChunk != NULL)
207
    {
208
        Mix_FreeChunk(DummyChunk);
209
        DummyChunk = NULL;
1471 terminx 210
    }
211
 
1487 terminx 212
    if (DummyBuffer  != NULL)
213
    {
214
        free(DummyBuffer);
215
        DummyBuffer = NULL;
1471 terminx 216
    }
217
 
1487 terminx 218
    Mix_CloseAudio();
1583 plagman 219
 
220
    SDL_DestroyMutex(EffectFence);
221
 
1487 terminx 222
    Initialised = 0;
1471 terminx 223
}
224
 
1481 terminx 225
int32_t SDLDrv_PCM_BeginPlayback(char *BufferStart, int32_t BufferSize,
1471 terminx 226
                                                int32_t NumDivisions, void ( *CallBackFunc )( void ) )
227
{
228
        if (!Initialised) {
229
                ErrorCode = SDLErr_Uninitialised;
230
                return SDLErr_Error;
231
        }
232
 
233
        if (Playing) {
1481 terminx 234
                SDLDrv_PCM_StopPlayback();
1471 terminx 235
        }
236
 
237
        MixBuffer = BufferStart;
238
        MixBufferSize = BufferSize;
239
        MixBufferCount = NumDivisions;
240
        MixBufferCurrent = 0;
241
        MixBufferUsed = 0;
242
        MixCallBack = CallBackFunc;
243
 
244
        // prime the buffer
245
        MixCallBack();
246
 
1473 terminx 247
        Mix_Resume(-1);
1471 terminx 248
 
249
    Playing = 1;
250
 
251
        return SDLErr_Ok;
252
}
253
 
1481 terminx 254
void SDLDrv_PCM_StopPlayback(void)
1471 terminx 255
{
256
        if (!Initialised || !Playing) {
257
                return;
258
        }
259
 
1473 terminx 260
    Mix_Pause(-1);
1471 terminx 261
 
262
        Playing = 0;
263
}
264
 
1481 terminx 265
void SDLDrv_PCM_Lock(void)
1471 terminx 266
{
1473 terminx 267
        if (InterruptsDisabled++)
268
            return;
269
 
1583 plagman 270
        SDL_LockMutex(EffectFence);
1471 terminx 271
}
272
 
1481 terminx 273
void SDLDrv_PCM_Unlock(void)
1471 terminx 274
{
1473 terminx 275
        if (--InterruptsDisabled)
276
            return;
277
 
1583 plagman 278
        SDL_UnlockMutex(EffectFence);
1471 terminx 279
}
280