/*****************************************************************************
 *                                                                           *
 * Module : SOUND.C                                                          *
 *                                                                           *
 * Gestion du son                                                            *
 *                                                                           *
 *****************************************************************************/


#include  <Exec/Types.h>
#include  <Devices/Audio.h>
#include  <Proto/Exec.h>

#include  "main.h"


/*
// Constantes pour l'émulation du PSG AY3-8912
*/
#define PRIORITE_SON          0

#define LONGUEUR_SAMPLE       2

#define LONGUEUR_BRUIT_BLANC  1024

#define PAL_CLOCK       3546895 
#define CPC_FREQ          62500

#define PER_AMIGA     ( PAL_CLOCK / CPC_FREQ / LONGUEUR_SAMPLE )


/*
// Utilisé pour la génération de sons par l'audio.device
*/
static struct MsgPort * replymp = NULL;

static struct IOAudio * Voie0 = NULL;
static struct IOAudio * Voie1 = NULL;
static struct IOAudio * Voie2 = NULL;
static struct IOAudio * Voie3 = NULL;

static UBYTE TabAllocVoie0[ 1 ] = { 1 };
static UBYTE TabAllocVoie1[ 1 ] = { 2 };
static UBYTE TabAllocVoie2[ 1 ] = { 4 };
static UBYTE TabAllocVoie3[ 1 ] = { 8 };

static UBYTE chip SonCarre[ LONGUEUR_SAMPLE ] = { 0x7F, 0x80 };

static UBYTE chip BruitBlanc[ LONGUEUR_BRUIT_BLANC ] =
    {
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F,
    0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F,
    0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80,
    0x7F, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F,
    0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F,
    0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x80,
    0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x80,
    0x7F, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F,
    0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x80, 0x7F, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80, 0x80,
    0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x80,
    0x80, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x80, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F,
    0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80,
    0x7F, 0x80, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80,
    0x7F, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x80,
    0x80, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F,
    0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x80,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x80, 0x7F, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x80,
    0x7F, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x7F,
    0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80, 0x80,
    0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
    0x80, 0x80, 0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x80, 0x80, 0x80, 0x80, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F,
    0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x7F, 0x7F, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x80,
    0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x80,
    0x7F, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x80, 0x80,
    0x80, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x80, 0x80, 0x7F,
    0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x7F,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80,
    0x80, 0x7F, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x7F,
    0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x7F, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x80, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x80, 0x80, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F,
    0x80, 0x80, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x7F, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x80, 0x7F, 0x80, 0x80, 0x80, 0x80,
    0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F,
    0x80, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x80, 0x80,
    0x7F, 0x80, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x7F,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80,
    0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80,
    0x80, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F,
    0x80, 0x80, 0x80, 0x80, 0x7F, 0x80, 0x7F, 0x80,
    0x80, 0x80, 0x80, 0x7F, 0x80, 0x80, 0x7F, 0x80,
    0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F,
    0x80, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x80,
    0x7F, 0x80, 0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F,
    0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80,
    0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x80, 0x7F, 0x80, 0x80, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80,
    0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x80, 0x80,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80,
    0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x80, 0x7F,
    0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x80, 0x7F, 0x80, 0x7F, 0x80,
    0x80, 0x7F, 0x7F, 0x7F, 0x80, 0x7F, 0x80, 0x80,
    0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x7F, 0x7F, 0x80,
    0x80, 0x80, 0x7F, 0x80, 0x80, 0x80, 0x7F, 0x7F,
    0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x80, 0x7F, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x7F, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x7F, 0x7F, 0x7F,
    0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x80
};


/*
// Initialisation : allocation de 3 canaux audios, préparation
// de la struction IOAudio pour chaque canal...
*/
BOOL InitSound( void )
{
    if ( ! IsSound )
        return( TRUE );

    replymp = ( struct MsgPort * )CreatePort( NULL, 0 );
    if ( ! replymp )
        return( FALSE );

    Voie0 = ( struct IOAudio * )CreateExtIO( replymp, sizeof( struct IOAudio ) );
    if ( ! Voie0 )
        return( FALSE );

    Voie0->ioa_Request.io_Message.mn_Node.ln_Pri = PRIORITE_SON;
    Voie0->ioa_Data = TabAllocVoie0;
    Voie0->ioa_Length = sizeof( TabAllocVoie0 );
    if ( OpenDevice( AUDIONAME, 0, ( struct IORequest * )Voie0, 0 ) )
        {
        Voie0->ioa_Request.io_Device = NULL;
        return( FALSE );
        }

    Voie1 = ( struct IOAudio * )CreateExtIO( replymp, sizeof( struct IOAudio ) );
    if ( ! Voie1 )
        return( FALSE );

    Voie1->ioa_Request.io_Message.mn_Node.ln_Pri = PRIORITE_SON;
    Voie1->ioa_Data = TabAllocVoie1;
    Voie1->ioa_Length = sizeof( TabAllocVoie1 );
    if ( OpenDevice( AUDIONAME, 0, ( struct IORequest * )Voie1, 0 ) )
        {
        Voie1->ioa_Request.io_Device = NULL;
        return( FALSE );
        }

    Voie2 = ( struct IOAudio * )CreateExtIO( replymp, sizeof( struct IOAudio ) );
    if ( ! Voie2 )
        return( FALSE );

    Voie2->ioa_Request.io_Message.mn_Node.ln_Pri = PRIORITE_SON;
    Voie2->ioa_Data = TabAllocVoie2;
    Voie2->ioa_Length = sizeof( TabAllocVoie2 );
    if ( OpenDevice( AUDIONAME, 0, ( struct IORequest * )Voie2, 0 ) )
        {
        Voie2->ioa_Request.io_Device = NULL;
        return( FALSE );
        }

    Voie3 = ( struct IOAudio * )CreateExtIO( replymp, sizeof( struct IOAudio ) );
    if ( ! Voie3 )
        return( FALSE );

    Voie3->ioa_Request.io_Message.mn_Node.ln_Pri = PRIORITE_SON;
    Voie3->ioa_Data = TabAllocVoie3;
    Voie3->ioa_Length = sizeof( TabAllocVoie3 );
    if ( OpenDevice( AUDIONAME, 0, ( struct IORequest * )Voie3, 0 ) )
        {
        Voie3->ioa_Request.io_Device = NULL;
        return( FALSE );
        }

    Voie0->ioa_Data = 
    Voie1->ioa_Data =
    Voie2->ioa_Data = SonCarre;
    Voie3->ioa_Data = BruitBlanc;

    Voie0->ioa_Length =
    Voie1->ioa_Length =
    Voie2->ioa_Length = LONGUEUR_SAMPLE;
    Voie3->ioa_Length = LONGUEUR_BRUIT_BLANC;

    Voie0->ioa_Cycles =
    Voie1->ioa_Cycles =
    Voie2->ioa_Cycles =
    Voie3->ioa_Cycles = 0;

    Voie0->ioa_Request.io_Command =
    Voie1->ioa_Request.io_Command =
    Voie2->ioa_Request.io_Command =
    Voie3->ioa_Request.io_Command = CMD_WRITE;

    Voie0->ioa_Request.io_Flags =
    Voie1->ioa_Request.io_Flags =
    Voie2->ioa_Request.io_Flags =
    Voie3->ioa_Request.io_Flags = ADIOF_PERVOL;

    Voie0->ioa_Period =
    Voie1->ioa_Period =
    Voie2->ioa_Period =
    Voie3->ioa_Period = 10000;

    Voie0->ioa_Volume =
    Voie1->ioa_Volume =
    Voie2->ioa_Volume =
    Voie3->ioa_Volume = 0;

    BeginIO( ( struct IORequest * )Voie0 );
    BeginIO( ( struct IORequest * )Voie1 );
    BeginIO( ( struct IORequest * )Voie2 );
    BeginIO( ( struct IORequest * )Voie3 );

    Voie0->ioa_Request.io_Command =
    Voie1->ioa_Request.io_Command =
    Voie2->ioa_Request.io_Command =
    Voie3->ioa_Request.io_Command = ADCMD_PERVOL;

    Voie0->ioa_Request.io_Flags =
    Voie1->ioa_Request.io_Flags =
    Voie2->ioa_Request.io_Flags =
    Voie3->ioa_Request.io_Flags = ADIOF_SYNCCYCLE;

    return( TRUE );
}


/*
// Fonction appelée avec le numéro du dernier registre du PSG écrit.
*/
void __asm PlaySound( register __d0 UBYTE numReg )
{
    UBYTE CurrReg = TabRegsPSG[ numReg ];

    switch( numReg )
        {
        case 0 :
        case 1 :
            Voie0->ioa_Period = PER_AMIGA * ( ( ( TabRegsPSG[ 1 ] & 15 ) << 8 ) + TabRegsPSG[ 0 ] );
            BeginIO( ( struct IORequest * )Voie0 );
            break;

        case 2 :
        case 3 :
            Voie1->ioa_Period = PER_AMIGA * ( ( ( TabRegsPSG[ 3 ] & 15 ) << 8 ) + TabRegsPSG[ 2 ] );
            BeginIO( ( struct IORequest * )Voie1 );
            break;

        case 4 :
        case 5 :
            Voie2->ioa_Period = PER_AMIGA * ( ( ( TabRegsPSG[ 5 ] & 15 ) << 8 ) + TabRegsPSG[ 4 ] );
            BeginIO( ( struct IORequest * )Voie2 );
            break;

        case 6 :
            Voie3->ioa_Period = PER_AMIGA * ( ( TabRegsPSG[ 6 ] & 0x1F ) << 2 );
            BeginIO( ( struct IORequest * )Voie3 );
            break;

        case 7 :
/*
            if ( CurrReg & 0x01 )
                Voie0->ioa_Volume = 0;
            else
                Voie0->ioa_Volume = TabRegsPSG[ 8 ] << 2;

            if ( CurrReg & 0x02 )
                Voie1->ioa_Volume = 0;
            else
                Voie1->ioa_Volume = TabRegsPSG[ 9 ] << 2;

            if ( CurrReg & 0x04 )
                Voie2->ioa_Volume = 0;
            else
                Voie2->ioa_Volume = TabRegsPSG[ 10 ] << 2;

            BeginIO( ( struct IORequest * )Voie0 );
            BeginIO( ( struct IORequest * )Voie1 );
            BeginIO( ( struct IORequest * )Voie2 );
*/
            Voie3->ioa_Volume = 0;
            if ( ! ( CurrReg & 0x8 ) )
                Voie3->ioa_Volume = ( TabRegsPSG[ 8 ] & 15 ) << 2;

            if ( ! ( CurrReg & 0x10 ) )
                Voie3->ioa_Volume = ( TabRegsPSG[ 9 ] & 15 ) << 2;

            if ( ! ( CurrReg & 0x20 ) )
                Voie3->ioa_Volume = ( TabRegsPSG[ 10 ] & 15 ) << 2;
            BeginIO( ( struct IORequest * )Voie3 );
            break;

        case 8 :
            Voie0->ioa_Volume = ( ( CurrReg & 15 ) << 2 );
            BeginIO( ( struct IORequest * )Voie0 );
            break;

        case 9 :
            Voie1->ioa_Volume = ( ( CurrReg & 15 ) << 2 );
            BeginIO( ( struct IORequest * )Voie1 );
            break;

        case 10 :
            Voie2->ioa_Volume = ( ( CurrReg & 15 ) << 2 );
            BeginIO( ( struct IORequest * )Voie2 );
            break;
        }
}


/*
// Libération des canaux audios.
*/
void EndSound( void )
{
    if ( IsSound )
        {
        if ( Voie0 && ! ( Voie0->ioa_Request.io_Error ) )
            {
            AbortIO( ( struct IORequest * )Voie0 );
            Voie0->ioa_Request.io_Command = ADCMD_FREE;
            DoIO( ( struct IORequest * )Voie0 );
            }

        if ( Voie1 && ! ( Voie1->ioa_Request.io_Error ) )
            {
            AbortIO( ( struct IORequest * )Voie1 );
            Voie1->ioa_Request.io_Command = ADCMD_FREE;
            DoIO( ( struct IORequest * )Voie1 );
            }

        if ( Voie2 && ! ( Voie2->ioa_Request.io_Error ) )
            {
            AbortIO( ( struct IORequest * )Voie2 );
            Voie2->ioa_Request.io_Command = ADCMD_FREE;
            DoIO( ( struct IORequest * )Voie2 );
            }

        if ( Voie3 && ! ( Voie3->ioa_Request.io_Error ) )
            {
            AbortIO( ( struct IORequest * )Voie3 );
            Voie3->ioa_Request.io_Command = ADCMD_FREE;
            DoIO( ( struct IORequest * )Voie3 );
            }

        if ( replymp )
            while( GetMsg( replymp ) )
                ;
  
        if ( Voie0 && Voie0->ioa_Request.io_Device )
            CloseDevice( ( struct IORequest * )Voie0 );

        if ( Voie1 && Voie1->ioa_Request.io_Device )
            CloseDevice( ( struct IORequest * )Voie1 );

        if ( Voie2 && Voie2->ioa_Request.io_Device )
            CloseDevice( ( struct IORequest * )Voie2 );

        if ( Voie3 && Voie3->ioa_Request.io_Device )
            CloseDevice( ( struct IORequest * )Voie3 );

        if ( replymp )
            DeletePort( replymp );

        if ( Voie0 )
            DeleteExtIO( ( struct IORequest * )Voie0 );

        if ( Voie1 )
            DeleteExtIO( ( struct IORequest * )Voie1 );

        if ( Voie2 )
            DeleteExtIO( ( struct IORequest * )Voie2 );

        if ( Voie3 )
            DeleteExtIO( ( struct IORequest * )Voie3 );
        }
}
