Subversion Repositories eduke32

Rev

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