effect_position.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 27 Dec 2002 15:13:37 +0000
changeset 201 e55fb6b45559
parent 159 01490534f9fe
child 218 a21e382190a8
permissions -rw-r--r--
(From Steven Fuller. --ryan.)

"Hi,

Here's a patch that fixes problems (attenuation on unsigned samples
would cause the samples to fall towards 0 when it should instead fall
towards 128/32768) when doing panning on 8-bit sounds and 16-bit unsigned
samples."
slouken@113
     1
/*
slouken@138
     2
    SDL_mixer:  An audio mixer library based on the SDL library
slouken@138
     3
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
slouken@113
     4
slouken@113
     5
    This library is free software; you can redistribute it and/or
slouken@113
     6
    modify it under the terms of the GNU Library General Public
slouken@113
     7
    License as published by the Free Software Foundation; either
slouken@113
     8
    version 2 of the License, or (at your option) any later version.
slouken@113
     9
slouken@113
    10
    This library is distributed in the hope that it will be useful,
slouken@113
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@113
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@113
    13
    Library General Public License for more details.
slouken@113
    14
slouken@113
    15
    You should have received a copy of the GNU Library General Public
slouken@113
    16
    License along with this library; if not, write to the Free
slouken@113
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@113
    18
slouken@113
    19
    This file by Ryan C. Gordon (icculus@linuxgames.com)
slouken@113
    20
slouken@113
    21
    These are some internally supported special effects that use SDL_mixer's
slouken@113
    22
    effect callback API. They are meant for speed over quality.  :)
slouken@113
    23
*/
slouken@113
    24
slouken@113
    25
/* $Id$ */
slouken@113
    26
slouken@113
    27
#include <stdio.h>
slouken@113
    28
#include <stdlib.h>
slouken@114
    29
#include <string.h>
slouken@114
    30
slouken@113
    31
#include "SDL.h"
slouken@113
    32
#include "SDL_mixer.h"
slouken@159
    33
#include "SDL_endian.h"
slouken@113
    34
slouken@113
    35
#define __MIX_INTERNAL_EFFECT__
slouken@113
    36
#include "effects_internal.h"
slouken@113
    37
slouken@113
    38
/* profile code:
slouken@113
    39
    #include <sys/time.h>
slouken@113
    40
    #include <unistd.h>
slouken@113
    41
    struct timeval tv1;
slouken@113
    42
    struct timeval tv2;
slouken@113
    43
    
slouken@113
    44
    gettimeofday(&tv1, NULL);
slouken@113
    45
slouken@113
    46
        ... do your thing here ...
slouken@113
    47
slouken@113
    48
    gettimeofday(&tv2, NULL);
slouken@113
    49
    printf("%ld\n", tv2.tv_usec - tv1.tv_usec);
slouken@113
    50
*/
slouken@113
    51
slouken@113
    52
slouken@113
    53
/*
slouken@113
    54
 * Positional effects...panning, distance attenuation, etc.
slouken@113
    55
 */
slouken@113
    56
slouken@113
    57
typedef struct _Eff_positionargs
slouken@113
    58
{
slouken@113
    59
    volatile float left_f;
slouken@113
    60
    volatile float right_f;
slouken@113
    61
    volatile Uint8 left_u8;
slouken@113
    62
    volatile Uint8 right_u8;
slouken@113
    63
    volatile float distance_f;
slouken@113
    64
    volatile Uint8 distance_u8;
slouken@113
    65
    volatile int in_use;
slouken@113
    66
    volatile int channels;
slouken@113
    67
} position_args;
slouken@113
    68
slouken@113
    69
static position_args **pos_args_array = NULL;
slouken@113
    70
static position_args *pos_args_global = NULL;
slouken@113
    71
static int position_channels = 0;
slouken@113
    72
slouken@113
    73
/* This just frees up the callback-specific data. */
slouken@113
    74
static void _Eff_PositionDone(int channel, void *udata)
slouken@113
    75
{
slouken@113
    76
    if (channel < 0) {
slouken@113
    77
        if (pos_args_global != NULL) {
slouken@113
    78
            free(pos_args_global);
slouken@113
    79
            pos_args_global = NULL;
slouken@113
    80
        }
slouken@113
    81
    }
slouken@113
    82
slouken@113
    83
    else if (pos_args_array[channel] != NULL) {
slouken@113
    84
        free(pos_args_array[channel]);
slouken@113
    85
        pos_args_array[channel] = NULL;
slouken@113
    86
    }
slouken@113
    87
}
slouken@113
    88
slouken@113
    89
slouken@113
    90
static void _Eff_position_u8(int chan, void *stream, int len, void *udata)
slouken@113
    91
{
slouken@113
    92
    volatile position_args *args = (volatile position_args *) udata;
slouken@113
    93
    Uint8 *ptr = (Uint8 *) stream;
slouken@113
    94
    int i;
slouken@113
    95
slouken@113
    96
        /*
slouken@113
    97
         * if there's only a mono channnel (the only way we wouldn't have
slouken@113
    98
         *  a len divisible by 2 here), then left_f and right_f are always
slouken@113
    99
         *  1.0, and are therefore throwaways.
slouken@113
   100
         */
slouken@113
   101
    if (len % sizeof (Uint16) != 0) {
slouken@113
   102
        *(ptr++) = (Uint8) (((float) *ptr) * args->distance_f);
slouken@113
   103
        len--;
slouken@113
   104
    }
slouken@113
   105
slouken@113
   106
    for (i = 0; i < len; i += sizeof (Uint8) * 2) {
icculus@201
   107
        /* must adjust the sample so that 0 is the center */
icculus@201
   108
        *(ptr++) = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) 
icculus@201
   109
            * args->left_f) * args->distance_f) + 128);
icculus@201
   110
        *(ptr++) = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) 
icculus@201
   111
            * args->right_f) * args->distance_f) + 128);
slouken@113
   112
    }
slouken@113
   113
}
slouken@113
   114
slouken@113
   115
slouken@113
   116
/*
slouken@113
   117
 * This one runs about 10.1 times faster than the non-table version, with
slouken@113
   118
 *  no loss in quality. It does, however, require 64k of memory for the
slouken@113
   119
 *  lookup table. Also, this will only update position information once per
slouken@113
   120
 *  call; the non-table version always checks the arguments for each sample,
slouken@113
   121
 *  in case the user has called Mix_SetPanning() or whatnot again while this
slouken@113
   122
 *  callback is running.
slouken@113
   123
 */
slouken@113
   124
static void _Eff_position_table_u8(int chan, void *stream, int len, void *udata)
slouken@113
   125
{
slouken@113
   126
    volatile position_args *args = (volatile position_args *) udata;
slouken@113
   127
    Uint8 *ptr = (Uint8 *) stream;
slouken@113
   128
    Uint32 *p;
slouken@113
   129
    int i;
slouken@113
   130
    Uint8 *l = ((Uint8 *) _Eff_volume_table) + (256 * args->left_u8);
slouken@113
   131
    Uint8 *r = ((Uint8 *) _Eff_volume_table) + (256 * args->right_u8);
slouken@113
   132
    Uint8 *d = ((Uint8 *) _Eff_volume_table) + (256 * args->distance_u8);
slouken@113
   133
slouken@113
   134
        /*
slouken@113
   135
         * if there's only a mono channnel, then l[] and r[] are always
slouken@113
   136
         *  volume 255, and are therefore throwaways. Still, we have to
slouken@113
   137
         *  be sure not to overrun the audio buffer...
slouken@113
   138
         */
slouken@113
   139
    while (len % sizeof (Uint32) != 0) {
slouken@113
   140
        *(ptr++) = d[l[*ptr]];
slouken@113
   141
        if (args->channels == 2)
slouken@113
   142
            *(ptr++) = d[r[*ptr]];
slouken@113
   143
        len -= args->channels;
slouken@113
   144
    }
slouken@113
   145
slouken@113
   146
    p = (Uint32 *) ptr;
slouken@113
   147
slouken@113
   148
    for (i = 0; i < len; i += sizeof (Uint32)) {
slouken@159
   149
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
slouken@113
   150
        *(p++) = (d[l[(*p & 0xFF000000) >> 24]] << 24) |
slouken@113
   151
                 (d[r[(*p & 0x00FF0000) >> 16]] << 16) |
slouken@113
   152
                 (d[l[(*p & 0x0000FF00) >>  8]] <<  8) |
slouken@113
   153
                 (d[r[(*p & 0x000000FF)      ]]      ) ;
slouken@113
   154
#else
slouken@113
   155
        *(p++) = (d[r[(*p & 0xFF000000) >> 24]] << 24) |
slouken@113
   156
                 (d[l[(*p & 0x00FF0000) >> 16]] << 16) |
slouken@113
   157
                 (d[r[(*p & 0x0000FF00) >>  8]] <<  8) |
slouken@113
   158
                 (d[l[(*p & 0x000000FF)      ]]      ) ;
slouken@113
   159
#endif
slouken@113
   160
    }
slouken@113
   161
}
slouken@113
   162
slouken@113
   163
slouken@113
   164
static void _Eff_position_s8(int chan, void *stream, int len, void *udata)
slouken@113
   165
{
slouken@113
   166
    volatile position_args *args = (volatile position_args *) udata;
slouken@113
   167
    Sint8 *ptr = (Sint8 *) stream;
slouken@113
   168
    int i;
slouken@113
   169
slouken@113
   170
        /*
slouken@113
   171
         * if there's only a mono channnel (the only way we wouldn't have
slouken@113
   172
         *  a len divisible by 2 here), then left_f and right_f are always
slouken@113
   173
         *  1.0, and are therefore throwaways.
slouken@113
   174
         */
slouken@113
   175
    if (len % sizeof (Sint16) != 0) {
slouken@113
   176
        *(ptr++) = (Sint8) (((float) *ptr) * args->distance_f);
slouken@113
   177
        len--;
slouken@113
   178
    }
slouken@113
   179
slouken@113
   180
    for (i = 0; i < len; i += sizeof (Sint8) * 2) {
slouken@113
   181
        *(ptr++) = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f);
slouken@113
   182
        *(ptr++) = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f);
slouken@113
   183
    }
slouken@113
   184
}
slouken@113
   185
slouken@113
   186
slouken@113
   187
/*
slouken@113
   188
 * This one runs about 10.1 times faster than the non-table version, with
slouken@113
   189
 *  no loss in quality. It does, however, require 64k of memory for the
slouken@113
   190
 *  lookup table. Also, this will only update position information once per
slouken@113
   191
 *  call; the non-table version always checks the arguments for each sample,
slouken@113
   192
 *  in case the user has called Mix_SetPanning() or whatnot again while this
slouken@113
   193
 *  callback is running.
slouken@113
   194
 */
slouken@113
   195
static void _Eff_position_table_s8(int chan, void *stream, int len, void *udata)
slouken@113
   196
{
slouken@113
   197
    volatile position_args *args = (volatile position_args *) udata;
slouken@113
   198
    Sint8 *ptr = (Sint8 *) stream;
slouken@113
   199
    Uint32 *p;
slouken@113
   200
    int i;
slouken@132
   201
    Sint8 *l = ((Sint8 *) _Eff_volume_table) + (256 * args->left_u8);
slouken@132
   202
    Sint8 *r = ((Sint8 *) _Eff_volume_table) + (256 * args->right_u8);
slouken@113
   203
    Sint8 *d = ((Sint8 *) _Eff_volume_table) + (256 * args->distance_u8);
slouken@113
   204
slouken@113
   205
slouken@113
   206
    while (len % sizeof (Uint32) != 0) {
slouken@113
   207
        *(ptr++) = d[l[*ptr]];
slouken@113
   208
        if (args->channels > 1)
slouken@113
   209
            *(ptr++) = d[r[*ptr]];
slouken@113
   210
        len -= args->channels;
slouken@113
   211
    }
slouken@113
   212
slouken@113
   213
    p = (Uint32 *) ptr;
slouken@113
   214
slouken@113
   215
    for (i = 0; i < len; i += sizeof (Uint32)) {
slouken@159
   216
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
slouken@113
   217
        *(p++) = (d[l[((Sint16)(Sint8)((*p & 0xFF000000) >> 24))+128]] << 24) |
slouken@113
   218
                 (d[r[((Sint16)(Sint8)((*p & 0x00FF0000) >> 16))+128]] << 16) |
slouken@113
   219
                 (d[l[((Sint16)(Sint8)((*p & 0x0000FF00) >>  8))+128]] <<  8) |
slouken@113
   220
                 (d[r[((Sint16)(Sint8)((*p & 0x000000FF)      ))+128]]      ) ;
slouken@113
   221
#else
slouken@113
   222
        *(p++) = (d[r[((Sint16)(Sint8)((*p & 0xFF000000) >> 24))+128]] << 24) |
slouken@113
   223
                 (d[l[((Sint16)(Sint8)((*p & 0x00FF0000) >> 16))+128]] << 16) |
slouken@113
   224
                 (d[r[((Sint16)(Sint8)((*p & 0x0000FF00) >>  8))+128]] <<  8) |
slouken@113
   225
                 (d[l[((Sint16)(Sint8)((*p & 0x000000FF)      ))+128]]      ) ;
slouken@113
   226
#endif
slouken@113
   227
    }
slouken@113
   228
slouken@113
   229
slouken@113
   230
}
slouken@113
   231
slouken@113
   232
slouken@113
   233
/* !!! FIXME : Optimize the code for 16-bit samples? */
slouken@113
   234
slouken@113
   235
static void _Eff_position_u16lsb(int chan, void *stream, int len, void *udata)
slouken@113
   236
{
slouken@113
   237
    volatile position_args *args = (volatile position_args *) udata;
slouken@113
   238
    Uint16 *ptr = (Uint16 *) stream;
slouken@113
   239
    int i;
slouken@113
   240
slouken@113
   241
    for (i = 0; i < len; i += sizeof (Uint16) * 2) {
slouken@159
   242
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
icculus@201
   243
        Sint16 sampl = (Sint16) (SDL_Swap16(*(ptr+0)) - 32768);
icculus@201
   244
        Sint16 sampr = (Sint16) (SDL_Swap16(*(ptr+1)) - 32768);
icculus@201
   245
        
icculus@201
   246
        Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
icculus@201
   247
                                    * args->distance_f) + 32768);
icculus@201
   248
        Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
icculus@201
   249
                                    * args->distance_f) + 32768);
icculus@201
   250
slouken@113
   251
        *(ptr++) = (Uint16) SDL_Swap16(swapl);
slouken@113
   252
        *(ptr++) = (Uint16) SDL_Swap16(swapr);
slouken@113
   253
#else
icculus@201
   254
        Sint16 sampl = (Sint16) (*(ptr+0) - 32768);
icculus@201
   255
        Sint16 sampr = (Sint16) (*(ptr+1) - 32768);
icculus@201
   256
icculus@201
   257
        *(ptr++) = (Uint16) ((Sint16) (((float) sampl * args->left_f) 
icculus@201
   258
                                    * args->distance_f) + 32768);
icculus@201
   259
        *(ptr++) = (Uint16) ((Sint16) (((float) sampr * args->right_f) 
icculus@201
   260
                                    * args->distance_f) + 32768);
slouken@113
   261
#endif
slouken@113
   262
    }
slouken@113
   263
}
slouken@113
   264
slouken@113
   265
static void _Eff_position_s16lsb(int chan, void *stream, int len, void *udata)
slouken@113
   266
{
slouken@113
   267
    /* 16 signed bits (lsb) * 2 channels. */
slouken@113
   268
    volatile position_args *args = (volatile position_args *) udata;
slouken@113
   269
    Sint16 *ptr = (Sint16 *) stream;
slouken@113
   270
    int i;
slouken@113
   271
slouken@113
   272
    for (i = 0; i < len; i += sizeof (Sint16) * 2) {
slouken@159
   273
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
slouken@113
   274
        Sint16 swapl = (Sint16) ((((float) SDL_Swap16(*(ptr))) *
slouken@113
   275
                                    args->left_f) * args->distance_f);
slouken@159
   276
        Sint16 swapr = (Sint16) ((((float) SDL_Swap16(*(ptr+1))) *
slouken@113
   277
                                    args->right_f) * args->distance_f);
slouken@113
   278
        *(ptr++) = (Sint16) SDL_Swap16(swapl);
slouken@113
   279
        *(ptr++) = (Sint16) SDL_Swap16(swapr);
slouken@113
   280
#else
slouken@113
   281
        *(ptr++) = (Sint16) ((((float) *ptr)*args->left_f)*args->distance_f);
slouken@113
   282
        *(ptr++) = (Sint16) ((((float) *ptr)*args->right_f)*args->distance_f);
slouken@113
   283
#endif
slouken@113
   284
    }
slouken@113
   285
}
slouken@113
   286
slouken@113
   287
static void _Eff_position_u16msb(int chan, void *stream, int len, void *udata)
slouken@113
   288
{
slouken@113
   289
    /* 16 signed bits (lsb) * 2 channels. */
slouken@113
   290
    volatile position_args *args = (volatile position_args *) udata;
slouken@113
   291
    Uint16 *ptr = (Uint16 *) stream;
slouken@113
   292
    int i;
slouken@113
   293
slouken@113
   294
    for (i = 0; i < len; i += sizeof (Sint16) * 2) {
slouken@159
   295
#if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
icculus@201
   296
        Sint16 sampl = (Sint16) (SDL_Swap16(*(ptr+0)) - 32768);
icculus@201
   297
        Sint16 sampr = (Sint16) (SDL_Swap16(*(ptr+1)) - 32768);
icculus@201
   298
        
icculus@201
   299
        Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
icculus@201
   300
                                    * args->distance_f) + 32768);
icculus@201
   301
        Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
icculus@201
   302
                                    * args->distance_f) + 32768);
icculus@201
   303
slouken@113
   304
        *(ptr++) = (Uint16) SDL_Swap16(swapl);
slouken@113
   305
        *(ptr++) = (Uint16) SDL_Swap16(swapr);
slouken@113
   306
#else
icculus@201
   307
        Sint16 sampl = (Sint16) (*(ptr+0) - 32768);
icculus@201
   308
        Sint16 sampr = (Sint16) (*(ptr+1) - 32768);
icculus@201
   309
icculus@201
   310
        *(ptr++) = (Uint16) ((Sint16) (((float) sampl * args->left_f) 
icculus@201
   311
                                    * args->distance_f) + 32768);
icculus@201
   312
        *(ptr++) = (Uint16) ((Sint16) (((float) sampr * args->right_f) 
icculus@201
   313
                                    * args->distance_f) + 32768);
slouken@113
   314
#endif
slouken@113
   315
    }
slouken@113
   316
}
slouken@113
   317
slouken@113
   318
static void _Eff_position_s16msb(int chan, void *stream, int len, void *udata)
slouken@113
   319
{
slouken@113
   320
    /* 16 signed bits (lsb) * 2 channels. */
slouken@113
   321
    volatile position_args *args = (volatile position_args *) udata;
slouken@113
   322
    Sint16 *ptr = (Sint16 *) stream;
slouken@113
   323
    int i;
slouken@113
   324
slouken@113
   325
    for (i = 0; i < len; i += sizeof (Sint16) * 2) {
slouken@159
   326
#if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
slouken@113
   327
        Sint16 swapl = (Sint16) ((((float) SDL_Swap16(*(ptr))) *
slouken@113
   328
                                    args->left_f) * args->distance_f);
slouken@159
   329
        Sint16 swapr = (Sint16) ((((float) SDL_Swap16(*(ptr+1))) *
slouken@113
   330
                                    args->right_f) * args->distance_f);
slouken@113
   331
        *(ptr++) = (Sint16) SDL_Swap16(swapl);
slouken@113
   332
        *(ptr++) = (Sint16) SDL_Swap16(swapr);
slouken@113
   333
#else
slouken@113
   334
        *(ptr++) = (Sint16) ((((float) *ptr)*args->left_f)*args->distance_f);
slouken@113
   335
        *(ptr++) = (Sint16) ((((float) *ptr)*args->right_f)*args->distance_f);
slouken@113
   336
#endif
slouken@113
   337
    }
slouken@113
   338
}
slouken@113
   339
slouken@113
   340
slouken@113
   341
static void init_position_args(position_args *args)
slouken@113
   342
{
slouken@113
   343
    memset(args, '\0', sizeof (position_args));
slouken@113
   344
    args->in_use = 0;
slouken@113
   345
    args->left_u8 = args->right_u8 = args->distance_u8 = 255;
slouken@113
   346
    args->left_f  = args->right_f  = args->distance_f  = 1.0f;
slouken@113
   347
    Mix_QuerySpec(NULL, NULL, (int *) &args->channels);
slouken@113
   348
}
slouken@113
   349
slouken@113
   350
slouken@113
   351
static position_args *get_position_arg(int channel)
slouken@113
   352
{
slouken@113
   353
    void *rc;
slouken@113
   354
    int i;
slouken@113
   355
slouken@113
   356
    if (channel < 0) {
slouken@113
   357
        if (pos_args_global == NULL) {
slouken@113
   358
            pos_args_global = malloc(sizeof (position_args));
slouken@113
   359
            if (pos_args_global == NULL) {
slouken@113
   360
                Mix_SetError("Out of memory");
slouken@113
   361
                return(NULL);
slouken@113
   362
            }
slouken@113
   363
            init_position_args(pos_args_global);
slouken@113
   364
        }
slouken@113
   365
slouken@113
   366
        return(pos_args_global);
slouken@113
   367
    }
slouken@113
   368
slouken@113
   369
    if (channel >= position_channels) {
slouken@113
   370
        rc = realloc(pos_args_array, (channel + 1) * sizeof (position_args *));
slouken@113
   371
        if (rc == NULL) {
slouken@113
   372
            Mix_SetError("Out of memory");
slouken@113
   373
            return(NULL);
slouken@113
   374
        }
slouken@113
   375
        pos_args_array = (position_args **) rc;
slouken@113
   376
        for (i = position_channels; i <= channel; i++) {
slouken@113
   377
            pos_args_array[i] = NULL;
slouken@113
   378
        }
slouken@113
   379
        position_channels = channel + 1;
slouken@113
   380
    }
slouken@113
   381
slouken@113
   382
    if (pos_args_array[channel] == NULL) {
slouken@113
   383
        pos_args_array[channel] = (position_args *)malloc(sizeof(position_args));
slouken@113
   384
        if (pos_args_array[channel] == NULL) {
slouken@113
   385
            Mix_SetError("Out of memory");
slouken@113
   386
            return(NULL);
slouken@113
   387
        }
slouken@113
   388
        init_position_args(pos_args_array[channel]);
slouken@113
   389
    }
slouken@113
   390
slouken@113
   391
    return(pos_args_array[channel]);
slouken@113
   392
}
slouken@113
   393
slouken@113
   394
slouken@113
   395
static Mix_EffectFunc_t get_position_effect_func(Uint16 format)
slouken@113
   396
{
slouken@113
   397
    Mix_EffectFunc_t f = NULL;
slouken@113
   398
slouken@113
   399
    switch (format) {
slouken@113
   400
        case AUDIO_U8:
slouken@113
   401
            f = (_Eff_build_volume_table_u8()) ? _Eff_position_table_u8 :
slouken@113
   402
                                                 _Eff_position_u8;
slouken@113
   403
            break;
slouken@113
   404
slouken@113
   405
        case AUDIO_S8:
slouken@113
   406
            f = (_Eff_build_volume_table_s8()) ? _Eff_position_table_s8 :
slouken@113
   407
                                                 _Eff_position_s8;
slouken@113
   408
            break;
slouken@113
   409
slouken@113
   410
        case AUDIO_U16LSB:
slouken@113
   411
            f = _Eff_position_u16lsb;
slouken@113
   412
            break;
slouken@113
   413
slouken@113
   414
        case AUDIO_S16LSB:
slouken@113
   415
            f = _Eff_position_s16lsb;
slouken@113
   416
            break;
slouken@113
   417
slouken@113
   418
        case AUDIO_U16MSB:
slouken@113
   419
            f = _Eff_position_u16msb;
slouken@113
   420
            break;
slouken@113
   421
slouken@113
   422
        case AUDIO_S16MSB:
slouken@113
   423
            f = _Eff_position_s16msb;
slouken@113
   424
            break;
slouken@113
   425
slouken@113
   426
        default:
slouken@113
   427
            Mix_SetError("Unsupported audio format");
slouken@113
   428
    }
slouken@113
   429
slouken@113
   430
    return(f);
slouken@113
   431
}
slouken@113
   432
slouken@113
   433
slouken@113
   434
int Mix_SetPanning(int channel, Uint8 left, Uint8 right)
slouken@113
   435
{
slouken@113
   436
    Mix_EffectFunc_t f = NULL;
slouken@113
   437
    int channels;
slouken@113
   438
    Uint16 format;
slouken@113
   439
    position_args *args = NULL;
slouken@113
   440
slouken@113
   441
    Mix_QuerySpec(NULL, &format, &channels);
slouken@113
   442
slouken@113
   443
    if (channels != 2)    /* it's a no-op; we call that successful. */
slouken@113
   444
        return(1);
slouken@113
   445
slouken@113
   446
    f = get_position_effect_func(format);
slouken@113
   447
    if (f == NULL)
slouken@113
   448
        return(0);
slouken@113
   449
slouken@113
   450
    args = get_position_arg(channel);
slouken@113
   451
    if (!args)
slouken@113
   452
        return(0);
slouken@113
   453
slouken@113
   454
        /* it's a no-op; unregister the effect, if it's registered. */
slouken@113
   455
    if ((args->distance_u8 == 255) && (left == 255) &&
slouken@113
   456
        (right == 255) && (args->in_use))
slouken@113
   457
    {
slouken@113
   458
        return(Mix_UnregisterEffect(channel, f));
slouken@113
   459
    }
slouken@113
   460
slouken@113
   461
    args->left_u8 = left;
slouken@113
   462
    args->right_u8 = right;
slouken@114
   463
    args->left_f = ((float) left) / 255.0f;
slouken@114
   464
    args->right_f = ((float) right) / 255.0f;
slouken@113
   465
    if (!args->in_use) {
slouken@113
   466
        args->in_use = 1;
slouken@113
   467
        return(Mix_RegisterEffect(channel, f, _Eff_PositionDone, (void *) args));
slouken@113
   468
    }
slouken@113
   469
slouken@113
   470
    return(1);
slouken@113
   471
}
slouken@113
   472
slouken@113
   473
slouken@113
   474
int Mix_SetDistance(int channel, Uint8 distance)
slouken@113
   475
{
slouken@113
   476
    Mix_EffectFunc_t f = NULL;
slouken@113
   477
    Uint16 format;
slouken@113
   478
    position_args *args = NULL;
slouken@113
   479
slouken@113
   480
    Mix_QuerySpec(NULL, &format, NULL);
slouken@113
   481
    f = get_position_effect_func(format);
slouken@113
   482
    if (f == NULL)
slouken@113
   483
        return(0);
slouken@113
   484
slouken@113
   485
    args = get_position_arg(channel);
slouken@113
   486
    if (!args)
slouken@113
   487
        return(0);
slouken@113
   488
slouken@113
   489
    distance = 255 - distance;  /* flip it to our scale. */
slouken@113
   490
slouken@113
   491
        /* it's a no-op; unregister the effect, if it's registered. */
slouken@113
   492
    if ((distance == 255) && (args->left_u8 == 255) &&
slouken@113
   493
        (args->right_u8 == 255) && (args->in_use))
slouken@113
   494
    {
slouken@113
   495
        return(Mix_UnregisterEffect(channel, f));
slouken@113
   496
    }
slouken@113
   497
slouken@113
   498
    args->distance_u8 = distance;
slouken@114
   499
    args->distance_f = ((float) distance) / 255.0f;
slouken@113
   500
    if (!args->in_use) {
slouken@113
   501
        args->in_use = 1;
slouken@113
   502
        return(Mix_RegisterEffect(channel, f, _Eff_PositionDone, (void *) args));
slouken@113
   503
    }
slouken@113
   504
slouken@113
   505
    return(1);
slouken@113
   506
}
slouken@113
   507
slouken@113
   508
slouken@113
   509
int Mix_SetPosition(int channel, Sint16 angle, Uint8 distance)
slouken@113
   510
{
slouken@113
   511
    Mix_EffectFunc_t f = NULL;
slouken@113
   512
    Uint16 format;
slouken@113
   513
    int channels;
slouken@113
   514
    position_args *args = NULL;
slouken@113
   515
    Uint8 left = 255, right = 255;
slouken@113
   516
slouken@113
   517
    Mix_QuerySpec(NULL, &format, &channels);
slouken@113
   518
    f = get_position_effect_func(format);
slouken@113
   519
    if (f == NULL)
slouken@113
   520
        return(0);
slouken@113
   521
slouken@113
   522
        /* unwind the angle...it'll be between 0 and 359. */
slouken@113
   523
    while (angle >= 360) angle -= 360;
slouken@113
   524
    while (angle < 0) angle += 360;
slouken@113
   525
slouken@113
   526
    args = get_position_arg(channel);
slouken@113
   527
    if (!args)
slouken@113
   528
        return(0);
slouken@113
   529
slouken@113
   530
        /* it's a no-op; unregister the effect, if it's registered. */
slouken@113
   531
    if ((!distance) && (!angle) && (args->in_use))
slouken@113
   532
        return(Mix_UnregisterEffect(channel, f));
slouken@113
   533
slouken@113
   534
    if (channels == 2)
slouken@113
   535
    {
slouken@113
   536
        /*
slouken@113
   537
         * We only attenuate by position if the angle falls on the far side
slouken@113
   538
         *  of center; That is, an angle that's due north would not attenuate
slouken@113
   539
         *  either channel. Due west attenuates the right channel to 0.0, and
slouken@113
   540
         *  due east attenuates the left channel to 0.0. Slightly east of
slouken@113
   541
         *  center attenuates the left channel a little, and the right channel
slouken@113
   542
         *  not at all. I think of this as occlusion by one's own head.  :)
slouken@113
   543
         *
slouken@113
   544
         *   ...so, we split our angle circle into four quadrants...
slouken@113
   545
         */
slouken@113
   546
        if (angle < 90) {
slouken@113
   547
            left = 255 - ((Uint8) (255.0f * (((float) angle) / 89.0f)));
slouken@113
   548
        } else if (angle < 180) {
slouken@113
   549
            left = (Uint8) (255.0f * (((float) (angle - 90)) / 89.0f));
slouken@113
   550
        } else if (angle < 270) {
slouken@113
   551
            right = 255 - ((Uint8) (255.0f * (((float) (angle - 180)) / 89.0f)));
slouken@113
   552
        } else {
slouken@113
   553
            right = (Uint8) (255.0f * (((float) (angle - 270)) / 89.0f));
slouken@113
   554
        }
slouken@113
   555
    }
slouken@113
   556
slouken@113
   557
    distance = 255 - distance;  /* flip it to scale Mix_SetDistance() uses. */
slouken@113
   558
slouken@113
   559
    args->left_u8 = left;
slouken@114
   560
    args->left_f = ((float) left) / 255.0f;
slouken@113
   561
    args->right_u8 = right;
slouken@114
   562
    args->right_f = ((float) right) / 255.0f;
slouken@113
   563
    args->distance_u8 = distance;
slouken@114
   564
    args->distance_f = ((float) distance) / 255.0f;
slouken@113
   565
    if (!args->in_use) {
slouken@113
   566
        args->in_use = 1;
slouken@113
   567
        return(Mix_RegisterEffect(channel, f, _Eff_PositionDone, (void *) args));
slouken@113
   568
    }
slouken@113
   569
slouken@113
   570
    return(1);
slouken@113
   571
}
slouken@113
   572
slouken@113
   573
slouken@113
   574
/* end of effects_position.c ... */
slouken@113
   575