SDL_sound_internal.h
author Ozkan Sezer <sezero@users.sourceforge.net>
Wed, 24 May 2017 11:28:05 -0400
changeset 599 f0d57c9b72d8
parent 552 2e8907ff98e9
child 601 5b36839bb796
permissions -rw-r--r--
timidity.c: fix potential buffer overrun in RWgets

(num_read check was off-by-one.) also simplify the procedure a bit.
(transplanted from 0c4026dd32742e8b7d33fb96d40fe3c03b02f90c)
icculus@4
     1
/*
icculus@4
     2
 * SDL_sound -- An abstract sound format decoding API.
icculus@4
     3
 * Copyright (C) 2001  Ryan C. Gordon.
icculus@4
     4
 *
icculus@4
     5
 * This library is free software; you can redistribute it and/or
icculus@4
     6
 * modify it under the terms of the GNU Lesser General Public
icculus@4
     7
 * License as published by the Free Software Foundation; either
icculus@4
     8
 * version 2.1 of the License, or (at your option) any later version.
icculus@4
     9
 *
icculus@4
    10
 * This library is distributed in the hope that it will be useful,
icculus@4
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
icculus@4
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
icculus@4
    13
 * Lesser General Public License for more details.
icculus@4
    14
 *
icculus@4
    15
 * You should have received a copy of the GNU Lesser General Public
icculus@4
    16
 * License along with this library; if not, write to the Free Software
icculus@4
    17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
icculus@4
    18
 */
icculus@4
    19
icculus@4
    20
/*
icculus@4
    21
 * Internal function/structure declaration. Do NOT include in your
icculus@4
    22
 *  application.
icculus@4
    23
 *
icculus@552
    24
 * Please see the file LICENSE.txt in the source's root directory.
icculus@4
    25
 *
icculus@526
    26
 *  This file written by Ryan C. Gordon. (icculus@icculus.org)
icculus@4
    27
 */
icculus@4
    28
icculus@4
    29
#ifndef _INCLUDE_SDL_SOUND_INTERNAL_H_
icculus@4
    30
#define _INCLUDE_SDL_SOUND_INTERNAL_H_
icculus@4
    31
icculus@4
    32
#ifndef __SDL_SOUND_INTERNAL__
icculus@4
    33
#error Do not include this header from your applications.
icculus@4
    34
#endif
icculus@4
    35
icculus@4
    36
#include "SDL.h"
icculus@4
    37
icculus@401
    38
/* SDL 1.2.4 defines this, but better safe than sorry. */
icculus@401
    39
#if (!defined(__inline__))
icculus@401
    40
#  define __inline__
icculus@301
    41
#endif
icculus@301
    42
icculus@12
    43
#if (defined DEBUG_CHATTER)
icculus@62
    44
#define SNDDBG(x) printf x
icculus@12
    45
#else
icculus@62
    46
#define SNDDBG(x)
icculus@12
    47
#endif
icculus@12
    48
icculus@377
    49
#if HAVE_ASSERT_H
icculus@377
    50
#  include <assert.h>
icculus@377
    51
#endif
icculus@377
    52
icculus@377
    53
#ifdef _WIN32_WCE
icculus@377
    54
    extern char *strrchr(const char *s, int c);
icculus@377
    55
#   ifdef NDEBUG
icculus@377
    56
#       define assert(x)
icculus@377
    57
#   else
icculus@377
    58
#       define assert(x) if(!x) { fprintf(stderr,"Assertion failed in %s, line %s.\n",__FILE__,__LINE__); fclose(stderr); fclose(stdout); exit(1); }
icculus@377
    59
#   endif
icculus@377
    60
#endif
icculus@377
    61
 
icculus@377
    62
icculus@377
    63
#if (!defined assert)  /* if all else fails. */
icculus@377
    64
#  define assert(x)
icculus@377
    65
#endif
icculus@377
    66
icculus@377
    67
icculus@485
    68
/*
icculus@485
    69
 * SDL itself only supports mono and stereo output, but hopefully we can
icculus@485
    70
 *  raise this value someday...there's probably a lot of assumptions in
icculus@485
    71
 *  SDL_sound that rely on it, though.
icculus@485
    72
 */
icculus@485
    73
#define MAX_CHANNELS 2
icculus@485
    74
icculus@485
    75
icculus@4
    76
typedef struct __SOUND_DECODERFUNCTIONS__
icculus@4
    77
{
icculus@4
    78
        /* This is a block of info about your decoder. See SDL_sound.h. */
icculus@4
    79
    const Sound_DecoderInfo info;
icculus@4
    80
icculus@4
    81
        /*
icculus@42
    82
         * This is called during the Sound_Init() function. Use this to
icculus@42
    83
         *  set up any global state that your decoder needs, such as
icculus@42
    84
         *  initializing an external library, etc.
icculus@42
    85
         *
icculus@42
    86
         * Return non-zero if initialization is successful, zero if there's
icculus@42
    87
         *  a fatal error. If this method fails, then this decoder is
icculus@42
    88
         *  flagged as unavailable until SDL_sound() is shut down and
icculus@42
    89
         *  reinitialized, in which case this method will be tried again.
icculus@42
    90
         *
icculus@42
    91
         * Note that the decoders quit() method won't be called if this
icculus@42
    92
         *  method fails, so if you can't intialize, you'll have to clean
icculus@42
    93
         *  up the half-initialized state in this method.
icculus@42
    94
         */
icculus@42
    95
    int (*init)(void);
icculus@42
    96
icculus@42
    97
        /*
icculus@42
    98
         * This is called during the Sound_Quit() function. Use this to
icculus@42
    99
         *  clean up any global state that your decoder has used during its
icculus@42
   100
         *  lifespan.
icculus@42
   101
         */
icculus@42
   102
    void (*quit)(void);
icculus@42
   103
icculus@42
   104
        /*
icculus@4
   105
         * Returns non-zero if (sample) has a valid fileformat that this
icculus@4
   106
         *  driver can handle. Zero if this driver can NOT handle the data.
icculus@4
   107
         *
icculus@4
   108
         * Extension, which may be NULL, is just a hint as to the form of
icculus@4
   109
         *  data that is being passed in. Most decoders should determine if
icculus@4
   110
         *  they can handle the data by the data itself, but others, like
icculus@4
   111
         *  the raw data handler, need this hint to know if they should
icculus@4
   112
         *  accept the data in the first place.
icculus@4
   113
         *
icculus@4
   114
         * (sample)'s (opaque) field should be cast to a Sound_SampleInternal
icculus@4
   115
         *  pointer:
icculus@4
   116
         *
icculus@4
   117
         *   Sound_SampleInternal *internal;
icculus@4
   118
         *   internal = (Sound_SampleInternal *) sample->opaque;
icculus@4
   119
         *
icculus@4
   120
         * Certain fields of sample will be filled in for the decoder before
icculus@4
   121
         *  this call, and others should be filled in by the decoder. Some
icculus@4
   122
         *  fields are offlimits, and should NOT be modified. The list:
icculus@4
   123
         *
icculus@4
   124
         * in Sound_SampleInternal section:
icculus@4
   125
         *    Sound_Sample *next;  (offlimits)
icculus@4
   126
         *    Sound_Sample *prev;  (offlimits)
icculus@4
   127
         *    SDL_RWops *rw;       (can use, but do NOT close it)
icculus@4
   128
         *    const Sound_DecoderFunctions *funcs; (that's this structure)
icculus@143
   129
         *    Sound_AudioCVT sdlcvt; (offlimits)
icculus@4
   130
         *    void *buffer;        (offlimits until read() method)
icculus@4
   131
         *    Uint32 buffer_size;  (offlimits until read() method)
icculus@12
   132
         *    void *decoder_private; (read and write access)
icculus@4
   133
         *
icculus@4
   134
         * in rest of Sound_Sample:
icculus@4
   135
         *    void *opaque;        (this was internal section, above)
icculus@4
   136
         *    const Sound_DecoderInfo *decoder;  (read only)
icculus@4
   137
         *    Sound_AudioInfo desired; (read only, usually not needed here)
icculus@4
   138
         *    Sound_AudioInfo actual;  (please fill this in)
icculus@4
   139
         *    void *buffer;            (offlimits)
icculus@4
   140
         *    Uint32 buffer_size;      (offlimits)
icculus@4
   141
         *    Sound_SampleFlags flags; (set appropriately)
icculus@4
   142
         */
icculus@4
   143
    int (*open)(Sound_Sample *sample, const char *ext);
icculus@4
   144
icculus@4
   145
        /*
icculus@4
   146
         * Clean up. SDL_sound is done with this sample, so the decoder should
icculus@4
   147
         *  clean up any resources it allocated. Anything that wasn't
icculus@4
   148
         *  explicitly allocated by the decoder should be LEFT ALONE, since
icculus@4
   149
         *  the higher-level SDL_sound layer will clean up its own mess.
icculus@4
   150
         */
icculus@4
   151
    void (*close)(Sound_Sample *sample);
icculus@4
   152
icculus@4
   153
        /*
icculus@4
   154
         * Get more data from (sample). The decoder should get a pointer to
icculus@4
   155
         *  the internal structure...
icculus@4
   156
         *
icculus@4
   157
         *   Sound_SampleInternal *internal;
icculus@4
   158
         *   internal = (Sound_SampleInternal *) sample->opaque;
icculus@4
   159
         *
icculus@4
   160
         *  ...and then start decoding. Fill in up to internal->buffer_size
icculus@4
   161
         *  bytes of decoded sound in the space pointed to by
icculus@4
   162
         *  internal->buffer. The encoded data is read in from internal->rw.
icculus@4
   163
         *  Data should be decoded in the format specified during the
icculus@4
   164
         *  decoder's open() method in the sample->actual field. The
icculus@4
   165
         *  conversion to the desired format is done at a higher level.
icculus@4
   166
         *
icculus@4
   167
         * The return value is the number of bytes decoded into
icculus@4
   168
         *  internal->buffer, which can be no more than internal->buffer_size,
icculus@4
   169
         *  but can be less. If it is less, you should set a state flag:
icculus@4
   170
         *
icculus@4
   171
         *   If there's just no more data (end of file, etc), then do:
icculus@4
   172
         *      sample->flags |= SOUND_SAMPLEFLAG_EOF;
icculus@4
   173
         *
icculus@4
   174
         *   If there's an unrecoverable error, then do:
icculus@387
   175
         *      __Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG);
icculus@4
   176
         *      sample->flags |= SOUND_SAMPLEFLAG_ERROR;
icculus@4
   177
         *
icculus@4
   178
         *   If there's more data, but you'd have to block for considerable
icculus@4
   179
         *    amounts of time to get at it, or there's a recoverable error,
icculus@4
   180
         *    then do:
icculus@387
   181
         *      __Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG);
icculus@4
   182
         *      sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
icculus@4
   183
         *
icculus@4
   184
         * SDL_sound will not call your read() method for any samples with
icculus@4
   185
         *  SOUND_SAMPLEFLAG_EOF or SOUND_SAMPLEFLAG_ERROR set. The
icculus@4
   186
         *  SOUND_SAMPLEFLAG_EAGAIN flag is reset before each call to this
icculus@4
   187
         *  method.
icculus@4
   188
         */
icculus@12
   189
    Uint32 (*read)(Sound_Sample *sample);
icculus@223
   190
icculus@223
   191
        /*
icculus@223
   192
         * Reset the decoding to the beginning of the stream. Nonzero on
icculus@223
   193
         *  success, zero on failure.
icculus@223
   194
         *  
icculus@223
   195
         * The purpose of this method is to allow for higher efficiency than
icculus@223
   196
         *  an application could get by just recreating the sample externally;
icculus@223
   197
         *  not only do they not have to reopen the RWops, reallocate buffers,
icculus@223
   198
         *  and potentially pass the data through several rejecting decoders,
icculus@223
   199
         *  but certain decoders will not have to recreate their existing
icculus@223
   200
         *  state (search for metadata, etc) since they already know they
icculus@223
   201
         *  have a valid audio stream with a given set of characteristics.
icculus@223
   202
         *
icculus@223
   203
         * The decoder is responsible for calling seek() on the associated
icculus@223
   204
         *  SDL_RWops. A failing call to seek() should be the ONLY reason that
icculus@223
   205
         *  this method should ever fail!
icculus@223
   206
         */
icculus@223
   207
    int (*rewind)(Sound_Sample *sample);
icculus@306
   208
icculus@306
   209
        /*
icculus@306
   210
         * Reposition the decoding to an arbitrary point. Nonzero on
icculus@306
   211
         *  success, zero on failure.
icculus@306
   212
         *  
icculus@306
   213
         * The purpose of this method is to allow for higher efficiency than
icculus@306
   214
         *  an application could get by just rewinding the sample and 
icculus@306
   215
         *  decoding to a given point.
icculus@306
   216
         *
icculus@306
   217
         * The decoder is responsible for calling seek() on the associated
icculus@306
   218
         *  SDL_RWops.
icculus@306
   219
         *
icculus@306
   220
         * If there is an error, try to recover so that the next read will
icculus@306
   221
         *  continue as if nothing happened.
icculus@306
   222
         */
icculus@306
   223
    int (*seek)(Sound_Sample *sample, Uint32 ms);
icculus@4
   224
} Sound_DecoderFunctions;
icculus@4
   225
icculus@4
   226
icculus@143
   227
/* A structure to hold a set of audio conversion filters and buffers */
icculus@143
   228
typedef struct Sound_AudioCVT
icculus@143
   229
{
icculus@143
   230
    int    needed;                  /* Set to 1 if conversion possible */
icculus@143
   231
    Uint16 src_format;              /* Source audio format */
icculus@143
   232
    Uint16 dst_format;              /* Target audio format */
icculus@143
   233
    double rate_incr;               /* Rate conversion increment */
icculus@143
   234
    Uint8  *buf;                    /* Buffer to hold entire audio data */
icculus@143
   235
    int    len;                     /* Length of original audio buffer */
icculus@143
   236
    int    len_cvt;                 /* Length of converted audio buffer */
icculus@143
   237
    int    len_mult;                /* buffer must be len*len_mult big */
icculus@143
   238
    double len_ratio;       /* Given len, final size is len*len_ratio */
icculus@143
   239
    void   (*filters[20])(struct Sound_AudioCVT *cvt, Uint16 *format);
icculus@143
   240
    int    filter_index;            /* Current audio conversion function */
icculus@143
   241
} Sound_AudioCVT;
icculus@143
   242
icculus@441
   243
extern SNDDECLSPEC int Sound_BuildAudioCVT(Sound_AudioCVT *cvt,
icculus@441
   244
                        Uint16 src_format, Uint8 src_channels, Uint32 src_rate,
icculus@441
   245
                        Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate,
icculus@441
   246
                        Uint32 dst_size);
icculus@441
   247
icculus@441
   248
extern SNDDECLSPEC int Sound_ConvertAudio(Sound_AudioCVT *cvt);
icculus@441
   249
icculus@441
   250
icculus@485
   251
typedef void (*MixFunc)(float *dst, void *src, Uint32 frames, float *gains);
icculus@441
   252
icculus@4
   253
typedef struct __SOUND_SAMPLEINTERNAL__
icculus@4
   254
{
icculus@4
   255
    Sound_Sample *next;
icculus@4
   256
    Sound_Sample *prev;
icculus@4
   257
    SDL_RWops *rw;
icculus@4
   258
    const Sound_DecoderFunctions *funcs;
icculus@143
   259
    Sound_AudioCVT sdlcvt;
icculus@4
   260
    void *buffer;
icculus@4
   261
    Uint32 buffer_size;
icculus@12
   262
    void *decoder_private;
icculus@477
   263
    Sint32 total_time;
icculus@485
   264
    Uint32 mix_position;
icculus@485
   265
    MixFunc mix;
icculus@4
   266
} Sound_SampleInternal;
icculus@4
   267
icculus@4
   268
icculus@4
   269
/* error messages... */
icculus@4
   270
#define ERR_IS_INITIALIZED       "Already initialized"
icculus@4
   271
#define ERR_NOT_INITIALIZED      "Not initialized"
icculus@4
   272
#define ERR_INVALID_ARGUMENT     "Invalid argument"
icculus@4
   273
#define ERR_OUT_OF_MEMORY        "Out of memory"
icculus@4
   274
#define ERR_NOT_SUPPORTED        "Operation not supported"
icculus@4
   275
#define ERR_UNSUPPORTED_FORMAT   "Sound format unsupported"
icculus@4
   276
#define ERR_NOT_A_HANDLE         "Not a file handle"
icculus@4
   277
#define ERR_NO_SUCH_FILE         "No such file"
icculus@4
   278
#define ERR_PAST_EOF             "Past end of file"
icculus@4
   279
#define ERR_IO_ERROR             "I/O error"
icculus@4
   280
#define ERR_COMPRESSION          "(De)compression error"
icculus@4
   281
#define ERR_PREV_ERROR           "Previous decoding already caused an error"
icculus@4
   282
#define ERR_PREV_EOF             "Previous decoding already triggered EOF"
icculus@306
   283
#define ERR_CANNOT_SEEK          "Sample is not seekable"
icculus@4
   284
icculus@4
   285
/*
icculus@4
   286
 * Call this to set the message returned by Sound_GetError().
icculus@4
   287
 *  Please only use the ERR_* constants above, or add new constants to the
icculus@4
   288
 *  above group, but I want these all in one place.
icculus@4
   289
 *
icculus@4
   290
 * Calling this with a NULL argument is a safe no-op.
icculus@4
   291
 */
icculus@306
   292
void __Sound_SetError(const char *err);
icculus@4
   293
icculus@306
   294
/*
icculus@306
   295
 * Call this to convert milliseconds to an actual byte position, based on
icculus@306
   296
 *  audio data characteristics.
icculus@306
   297
 */
icculus@306
   298
Uint32 __Sound_convertMsToBytePos(Sound_AudioInfo *info, Uint32 ms);
icculus@4
   299
icculus@4
   300
/*
icculus@4
   301
 * Use this if you need a cross-platform stricmp().
icculus@4
   302
 */
icculus@4
   303
int __Sound_strcasecmp(const char *x, const char *y);
icculus@4
   304
icculus@4
   305
icculus@4
   306
/* These get used all over for lessening code clutter. */
icculus@306
   307
#define BAIL_MACRO(e, r) { __Sound_SetError(e); return r; }
icculus@306
   308
#define BAIL_IF_MACRO(c, e, r) if (c) { __Sound_SetError(e); return r; }
icculus@4
   309
icculus@4
   310
icculus@4
   311
icculus@4
   312
icculus@4
   313
/*--------------------------------------------------------------------------*/
icculus@4
   314
/*--------------------------------------------------------------------------*/
icculus@4
   315
/*------------                                              ----------------*/
icculus@4
   316
/*------------  You MUST implement the following functions  ----------------*/
icculus@4
   317
/*------------        if porting to a new platform.         ----------------*/
icculus@4
   318
/*------------     (see platform/unix.c for an example)     ----------------*/
icculus@4
   319
/*------------                                              ----------------*/
icculus@4
   320
/*--------------------------------------------------------------------------*/
icculus@4
   321
/*--------------------------------------------------------------------------*/
icculus@4
   322
icculus@4
   323
icculus@4
   324
/* (None, right now.)  */
icculus@4
   325
icculus@4
   326
icculus@4
   327
#ifdef __cplusplus
icculus@4
   328
extern "C" {
icculus@4
   329
#endif
icculus@4
   330
icculus@4
   331
#endif /* defined _INCLUDE_SDL_SOUND_INTERNAL_H_ */
icculus@4
   332
icculus@4
   333
/* end of SDL_sound_internal.h ... */
icculus@4
   334