gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Out of practice - can you help me decypher this?

#175967 - Lazy1 - Sat Mar 12, 2011 5:04 am

Taking a look at the positioned sound code from the SDL/Id source:
I have no idea what is going on, it looks like a table of modifiers to either sound position or volume level.

Code:

*
==========================
=
= SetSoundLoc - Given the location of an object (in terms of global
=   coordinates, held in globalsoundx and globalsoundy), munges the values
=   for an approximate distance from the left and right ear, and puts
=   those values into leftchannel and rightchannel.
=
= JAB
=
==========================
*/

#define ATABLEMAX 15
static const byte righttable[ATABLEMAX][ATABLEMAX * 2] = {
{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0, 1, 3, 5, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 4, 0, 0, 0, 0, 0, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 4, 1, 0, 0, 0, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 5, 4, 2, 1, 0, 1, 2, 3, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 5, 4, 3, 2, 2, 3, 3, 5, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 4, 4, 4, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
};
static const byte lefttable[ATABLEMAX][ATABLEMAX * 2] = {
{ 8, 8, 8, 8, 8, 8, 8, 8, 5, 3, 1, 0, 0, 0, 0, 0, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 0, 0, 0, 0, 0, 4, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 1, 0, 0, 0, 1, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 3, 2, 1, 0, 1, 2, 4, 5, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 5, 3, 3, 2, 2, 3, 4, 5, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 4, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 6, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
};

static void SetSoundLoc(fixed gx, fixed gy)
{
   fixed xt, yt;
   int x, y;

// translate point to view centered coordinates
//
   gx -= viewx;
   gy -= viewy;

//
// calculate newx
//
   xt = FixedByFrac(gx,viewcos);
   yt = FixedByFrac(gy,viewsin);
   x = (xt - yt) >> TILESHIFT;

//
// calculate newy
//
   xt = FixedByFrac(gx,viewsin);
   yt = FixedByFrac(gy,viewcos);
   y = (yt + xt) >> TILESHIFT;

   if (y >= ATABLEMAX)
      y = ATABLEMAX - 1;
   else if (y <= -ATABLEMAX)
      y = -ATABLEMAX;
   if (x < 0)
      x = -x;
   if (x >= ATABLEMAX)
      x = ATABLEMAX - 1;

   leftchannel  =  lefttable[x][y + ATABLEMAX];
   rightchannel = righttable[x][y + ATABLEMAX];
}


Life issues aside I'm looking at Wolf3d more as I can, but I cannot imagine what operation is supposed to be applied from the values in the table.

#175968 - Ruben - Sat Mar 12, 2011 12:08 pm

From the looks of it, it calculates the distance between an object and another and applies the according sound level for effects. I suppose the point of the table was speed rather than calculating the vector length.

EDIT:
On further inspection, it appears to be an attenuation table - that is, the amount to SUBTRACT from the volume [ie, the further an object is, the more attenuation].

#175973 - Lazy1 - Sun Mar 13, 2011 9:18 pm

Cool, looking at the original sources seem to confirm this as well as suggesting positioned sound was only done on the SBPro.
Interesting stuff since I had no idea it supported the SBPro at all.

I guess the best way to modify this would be to make new tables except fill it with volume levels and play the same sound on 2 channels?

#175975 - elhobbs - Mon Mar 14, 2011 12:56 am

the ds sound channels support panning.

#175976 - Lazy1 - Mon Mar 14, 2011 1:48 am

It does, but I think volume adjustments are the way to go here.
I just quickly hacked it in and the results so far are mixed:

Good: Doors in the distance sound quieter
Bad: Non existent or unnoticeable left/right positioning

I only have channels 11-15 to work with since 0-10 will be used by Pate's AdLib emulator.
Even worse: I use 2 channels for this effect.

[Edit]
Got it working well with 2 channels, but that sucks since there can only be 2 sounds at once.
Maybe one channel can be used by combining the panning and expected volume levels somehow?

[Edit again]
It seems to work but I'm not sure the magic numbers used to get the panning value really do anything.

Code:

void VolumePanningHack( int LeftVolume, int RightVolume, int* Volume, int* Panning ) {
    /*
     * Easiest case first, if Left == Right then center the sound.
     */
    if ( LeftVolume == RightVolume ) {
        *Volume = LeftVolume;
        *Panning = 64;
    }
    /*
     * Left is louder than right, pan more to the left.
     */
    else if ( LeftVolume > RightVolume ) {
        *Volume = ( LeftVolume - ( LeftVolume - RightVolume ) );
        *Panning = 63 - ( LeftVolume - RightVolume );
    }
    /*
     * Right is louder than left, pan to the right.
     */
    else {
        *Volume = ( RightVolume - ( RightVolume - LeftVolume ) );
        *Panning = 64 + ( RightVolume - LeftVolume );
    }

    if ( *Volume < 0 ) *Volume = 0;
    if ( *Volume > 127 ) *Volume = 127;

    if ( *Panning < 0 ) *Panning = 0;
    if ( *Panning > 127 ) *Panning = 127;
}


Quick sound code, DON'T JUDGE ME! /cry
Code:

int FindFreeSoundChannel( void ) {
    int i;

    for ( i = 11; i <= 15; i++ ) {
        if ( ! ( SCHANNEL_CR( i ) & SCHANNEL_ENABLE ) )
            return i;
    }

    return -1;
}

void WolfSoundSVC( int ByteCount, void* UserData ) {
    u32 Data[ 4 ];
    int ChanL;
    int ChanR;

    fifoGetDatamsg( FIFO_USER_02, sizeof( Data ), ( u8* ) Data );
    ChanL = FindFreeSoundChannel( );
    ChanR = FindFreeSoundChannel( );

    if ( ChanL >= 11 && ChanL <= 15 && ChanR >= 11 && ChanL <= 15 ) {
        SCHANNEL_SOURCE( ChanL ) = Data[ 0 ];
        SCHANNEL_LENGTH( ChanL ) = Data[ 1 ] >> 2;
        SCHANNEL_TIMER( ChanL ) = SOUND_FREQ( 7000 );

        SCHANNEL_SOURCE( ChanR ) = Data[ 0 ];
        SCHANNEL_LENGTH( ChanR ) = Data[ 1 ] >> 2;
        SCHANNEL_TIMER( ChanR ) = SOUND_FREQ( 7000 );

        SCHANNEL_CR( ChanL ) = SCHANNEL_ENABLE | SOUND_VOL( Data[ 2 ] ) | SOUND_PAN( 64 ) | SOUND_FORMAT_8BIT | SOUND_ONE_SHOT;
        SCHANNEL_CR( ChanR ) = SCHANNEL_ENABLE | SOUND_VOL( Data[ 3 ] ) | SOUND_PAN( 64 ) | SOUND_FORMAT_8BIT | SOUND_ONE_SHOT;
    }
}


Code:

///////////////////////////////////////////////////////////////////////////
//
//   SD_PlaySound() - plays the specified sound on the appropriate hardware
//
///////////////////////////////////////////////////////////////////////////
boolean SD_PlaySound( soundnames sound ) {
    //SoundCommon* sc = ( SoundCommon* ) audiosegs[ STARTADLIBSOUNDS + sound ];
    int SoundPage;
    int SoundLength;
    void* SoundData;
    int x, y;

    if ( DigiMap[ sound ] != -1 ) {
        x = SoundIsPositioned == true ? LeftVolAdjust : 128;
        y = SoundIsPositioned == true ? RightVolAdjust : 128;

        SoundPage = DigiList[ 0 + ( DigiMap[ sound ] * 2 ) ];
        SoundLength = DigiList[ 1 + ( DigiMap[ sound ] * 2 ) ];

        PM_SetPageSize( SoundPage, SoundLength );
        SoundData = ( void* ) PM_GetSoundPage( SoundPage );

        EmitSound( SoundData, SoundLength, x, y );
        return true;
    }

   return false;
}

/*
==========================
=
= SetSoundLoc - Given the location of an object (in terms of global
=   coordinates, held in globalsoundx and globalsoundy), munges the values
=   for an approximate distance from the left and right ear, and puts
=   those values into leftchannel and rightchannel.
=
= JAB
=
==========================
*/
#define ATABLEMAX 15

static const byte RightVolTable[ ATABLEMAX ][ ATABLEMAX * 2 ] = {
    { 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 32, 128, 128, 128, 128, 128, 112, 80, 48, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 32, 64, 128, 128, 128, 128, 128, 96, 64, 32, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 32, 32, 64, 112, 128, 128, 128, 112, 96, 64, 32, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 32, 48, 64, 96, 112, 128, 112, 96, 80, 48, 16, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 32, 48, 64, 80, 96, 96, 80, 80, 48, 32, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 32, 32, 48, 64, 64, 64, 64, 48, 32, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 32, 32, 48, 48, 48, 32, 32, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 32, 32, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
};

static const byte LeftVolTable[ ATABLEMAX ][ ATABLEMAX * 2 ] = {
    { 8, 8, 8, 8, 8, 8, 8, 8, 48, 80, 112, 128, 128, 128, 128, 128, 32, 128, 128, 128, 128, 128, 128, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 32, 64, 96, 128, 128, 128, 128, 128, 64, 32, 128, 128, 128, 128, 128, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 32, 64, 96, 112, 128, 128, 128, 112, 64, 32, 32, 128, 128, 128, 128, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 128, 48, 80, 96, 112, 128, 112, 96, 64, 48, 32, 128, 128, 128, 128, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 32, 48, 80, 80, 96, 96, 80, 64, 48, 32, 128, 128, 128, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 128, 32, 48, 64, 64, 64, 64, 48, 32, 32, 128, 128, 128, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 128, 32, 32, 48, 48, 48, 32, 32, 128, 128, 128, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 128, 128, 32, 32, 128, 128, 128, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
};

static void SetSoundLoc(fixed gx, fixed gy)
{
   fixed xt, yt;
   int x, y;

// translate point to view centered coordinates
//
   gx -= viewx;
   gy -= viewy;

//
// calculate newx
//
   xt = FixedByFrac(gx,viewcos);
   yt = FixedByFrac(gy,viewsin);
   x = (xt - yt) >> TILESHIFT;

//
// calculate newy
//
   xt = FixedByFrac(gx,viewsin);
   yt = FixedByFrac(gy,viewcos);
   y = (yt + xt) >> TILESHIFT;

   if (y >= ATABLEMAX)
      y = ATABLEMAX - 1;
   else if (y <= -ATABLEMAX)
      y = -ATABLEMAX;
   if (x < 0)
      x = -x;
   if (x >= ATABLEMAX)
      x = ATABLEMAX - 1;

    LeftVolAdjust = LeftVolTable[ x ][ y + ATABLEMAX ];
    RightVolAdjust = RightVolTable[ x ][ y + ATABLEMAX ];
}

void PlaySoundLocGlobal( word s, int id, fixed gx, fixed gy ) {
    SoundIsPositioned = true;

    SetSoundLoc( gx, gy );
    SD_PlaySound( s );

    SoundIsPositioned = false;
}

void UpdateSoundLoc(fixed x, fixed y, int angle) {
    /*
     * Cannot implement this, sounds are fire and forget.
     */
}

void EmitSound( void* SoundBase, int Length, int LeftVol, int RightVol ) {
    u32 Data[ 4 ];

    if ( SoundBase == NULL )
        return;

    if ( LeftVol < 0 ) LeftVol = 0;
    if ( RightVol < 0 ) RightVol = 0;

    if ( LeftVol > 127 ) LeftVol = 127;
    if ( RightVol > 127 ) RightVol = 127;

    Data[ 0 ] = ( u32 ) SoundBase;
    Data[ 1 ] = ( u32 ) Length;
    Data[ 2 ] = ( u32 ) LeftVol;
    Data[ 3 ] = ( u32 ) RightVol;

    fifoSendDatamsg( FIFO_USER_02, sizeof( Data ), ( u8* ) Data );
}


Let me know if there are fatal flaws here, still getting back into things.

#175981 - sverx - Mon Mar 14, 2011 12:56 pm

to get the final volume you should add both values and subtract from 16, IMHO. So you'll get a volume 0-16 to give to the channel (0-127).
For panning, subtract the left from the right and, this way it'll be -8...+8. multiply by 16 and add 63 :) Dirty method but should work :D