/*
//////////////////////////////////////////////////////////////
//      SNDWAVE.C                                                                                       //
//////////////////////////////////////////////////////////////
//      Module d'exploitation des samples simples                               //
//      Version Win95 Pentium (sans MMX)                                                //
//////////////////////////////////////////////////////////////
*/


#include "sndwave.hxx"

#include <process.h>

#ifndef DISABLE_WAVE

//----définition des fonction assembleurs
#ifndef __WATCOMC__    
#define DECLARE_ASM_1_0(NOM_FUNCTION, REG_1) \
 extern void __cdecl NOM_FUNCTION##_(); \
 __inline void NOM_FUNCTION(long PARAM_1) \
   { \
     {__asm  pushad }; \
     {__asm  mov REG_1, PARAM_1 }; \
     NOM_FUNCTION##_();\
     {__asm  popad }\
   }

#define DECLARE_ASM_2_0(NOM_FUNCTION, REG_1, REG_2) \
 extern void __cdecl NOM_FUNCTION##_() ; \
 __inline void NOM_FUNCTION(long PARAM_1,long PARAM_2) \
   {\
     {__asm  pushad }; \
     {__asm  mov REG_1, PARAM_1}; \
     {__asm  mov REG_2, PARAM_2}; \
     NOM_FUNCTION##_();\
     {__asm  popad }; \
  }

#define DECLARE_ASM_3_0(NOM_FUNCTION, REG_1, REG_2, REG_3) \
 extern void __cdecl NOM_FUNCTION##_() ; \
 __inline void NOM_FUNCTION(long PARAM_1,long PARAM_2,long PARAM_3) \
   {\
     {__asm  pushad }; \
     {__asm  mov REG_1, PARAM_1}; \
     {__asm  mov REG_2, PARAM_2}; \
     {__asm  mov REG_3, PARAM_3}; \
     NOM_FUNCTION##_();\
     {__asm  popad }; \
  }

#else //__WATCOMC__ 

/* ************************************************************ */
/* ****** Definition des macros pour WATCOM C : *************** */
/* ************************************************************ */

#define DECLARE_ASM( NOM_FUNCTION ) \
 extern void __cdecl NOM_FUNCTION##_();


/* Macro de declaration de la fonction externe asm : */
#define DECLARE_ASM_6_0(NOM_FUNCTION,p1,p2,p3,p4,p5,p6) \ 
  extern void NOM_FUNCTION##(long p1, long p2, long p3, long p4, long p5, long p6)

#define DECLARE_ASM_5_0(NOM_FUNCTION,p1,p2,p3,p4,p5) \ 
  extern void NOM_FUNCTION##(long p1, long p2, long p3, long p4, long p5)

#define DECLARE_ASM_4_0(NOM_FUNCTION,p1,p2,p3,p4) \ 
  extern void NOM_FUNCTION##(long p1, long p2, long p3, long p4)

#define DECLARE_ASM_3_0(NOM_FUNCTION,p1,p2,p3) \ 
  extern void NOM_FUNCTION##(long p1, long p2, long p3)

#define DECLARE_ASM_2_0(NOM_FUNCTION,p1,p2) \ 
  extern void NOM_FUNCTION##(long p1, long p2)

#define DECLARE_ASM_1_0(NOM_FUNCTION,p1) \ 
  extern void NOM_FUNCTION##(long p1)

#endif	//__WATCOMC__
//------------------------------

#pragma message("Pentium FPU")

//--------- partie spécifique au Pentium
#ifdef REVERB
#define DELAY_REVERB 6000
#define COEF_REVERB 0.4
#pragma message("avec REVERB")
#else
#pragma message("sans REVERB")
#endif


#ifdef SURROUND
void* DataBufferSurroundBrut;   //tableau de 1*long ->4 octets par ech.
#ifdef FILTRE_SURROUND
#pragma message("avec DolbySurround avec filtrage")
void* DataBufferSurround;
#define TAILLE_FILTRE 32         // Max number of filter taps
short Filtre[TAILLE_FILTRE];
float FiltreFloat[TAILLE_FILTRE];
#else
#pragma message("avec DolbySurround sans filtrage")
#define OFFSET_SURROUND 8       //nb d'ech de déphasage
#endif //FILTRE_SURROUND
#endif //SURROUND

#ifdef __cplusplus
extern "C" {
#endif
//reverb
long DeltaReverb=-8008;//multiple de 8,non multiple de 32

#ifndef __WATCOMC__
DECLARE_ASM_2_0(genere,esi,eax);
DECLARE_ASM_3_0(genere_part,edi,eax,esi);
DECLARE_ASM_1_0(rajparam,esi);
DECLARE_ASM_1_0(checkconst,esi);
#else //_WATCOM
#define genere _genere
#define genere_part _genere_part
#define rajparam _rajparam
#define checkconst _checkconst
DECLARE_ASM_3_0(genere_part,adr,nb_octets,buffer);
DECLARE_ASM_2_0(genere,adr,nb_octets);
DECLARE_ASM_1_0(rajparam,buffer);
DECLARE_ASM_1_0(checkconst,buffer);
#pragma aux _genere parm [esi] [eax] modify [eax ebx ecx edx esi edi]
#pragma aux _genere_part parm [edi] [eax] [esi] modify [eax ebx ecx edx esi edi]
#pragma aux _rajparam parm [esi] modify [eax ebx ecx edx esi edi]
#pragma aux _checkconst parm [esi] modify [eax ebx ecx edx esi edi]
#endif //__WATCOMC__

int VolumeTotal;
long* plAdrInit;
long* plAdrMax;

DWORD ptrReverb_asm;
#ifdef __cplusplus
}
#endif

void CheckConst(void)
{
#ifdef DEBUG_SON
        BUFFER_DISPO buffer;

        buffer.pt_sign=sizeof(BUFFER_DISPO);
        buffer.inc_sign=1;
        buffer.pt_max=2;
        buffer.pt_loop=3;
        buffer.pt_zero=4;
        buffer.vol      =5;
        *((int*)&buffer.sample)=6;
        buffer.pan      =7;
        buffer.must_looping=8;
        buffer.is_playing=9;
        buffer.is_looping=10;
        buffer.is_mixing=11;
        buffer.DeltaPitch=12;
        buffer.DeltaTemps=13;
        *((int*)&buffer.coef_mag)=14;

        checkconst((long)&buffer);

        if (buffer.pt_sign!=0x48185000)
                exit(0);
#endif //DEBUG_SON
}

__inline void RajParamHard(BUFFER_DISPO* buffer)
{
        rajparam((long)buffer);
}
        

/*----------------------------------------------------------------------
                                Calcul de la suite du buffer
                                Entrées:adr=adresse cible
                nb_octets=nb d'octets à calculer
        Sortie:néant
        Appelé par SynchroSnd()
-----------------------------------------------------------------------*/
__inline void genere_buffer_16bits(void* adr,unsigned long nb_octets)
{
	genere((long)adr,(long)nb_octets);
}


#ifdef SURROUND

/*----------------------------------------------------------------
    conversion d'un tableau de int en tableau de float
    Entrées:data=pointeur sur le 1° élément à convertir
        nb_to_convert=nb de long à convertir
-----------------------------------------------------------------*/
/*
void long_to_float(long* data,int nb_to_convert)
{
    char pile_fpu[108];

    _asm {
        pushad

        fsave   dword ptr [pile_fpu]
        finit

        //---
        mov     ebx,dword ptr [data]
        mov     eax,dword ptr [nb_to_convert]   ;

        cmp     eax,4
        jl      loop2

loop1:
                                            ;0   1   2   3   
        fild    dword ptr [ebx]             ;d0
        fild    dword ptr [ebx+4]           ;d1  d0   
        fild    dword ptr [ebx+8]           ;d2  d1  d0
        fild    dword ptr [ebx+12]          ;d3  d2  d1  d0
        fxch    ST(3)                       ;d0  d2  d1  d3

        fstp    dword ptr [ebx]             ;d2  d1  d3
        fstp    dword ptr [ebx+8]           ;d1  d3
        fstp    dword ptr [ebx+4]           ;d3
        fstp    dword ptr [ebx+12]  

        sub     eax,4
        add     ebx,16

        cmp     eax,0
        jg      loop1

fin:
        add     eax,4
loop2:
        fild    dword ptr [ebx]
        fstp    dword ptr [ebx]
        
        add     ebx,4
        dec     eax

        cmp     eax,0
        jne     loop2
        //---

        frstor  dword ptr [pile_fpu]

        popad
    }
*/
    /*
    float* pf_adr;
    long* pl_adr;
    float tmp;
    int i;


    for (i=nb_to_convert,pf_adr=(float*)data,pl_adr=data;i>0;i--,pl_adr++,pf_adr++)
    {
        tmp=(float)*pl_adr;
        *pf_adr=tmp;
    }
    */
/*
}
*/

#ifdef FILTRE_SURROUND
/*-------------------------------------------------------------------
    Génération des coefs de la convolution dans le tableau coefs
    Entrées:coefs=pointeur du tableau de float contenant les coefs
        nb_coef=nb de coef à mettre dans le tableau
        freq=fréquence d'éechentillonage
        Sortie:néant
-------------------------------------------------------------------*/
void GenerateFilterFloat(float* coefs,int nb_coef,int freq)
{
#ifndef NSP_PI
#define NSP_PI  (3.14159265358979324)  
#endif
    
        int  center = nb_coef/2,i,k;
   double sum;
   float freq1 = 100.0f/((float)freq/2);
   float freq2 = 7000.0f/((float)freq/2);

        double *FFirTab=(double *)SND_fn_pvMallocSnd(nb_coef*sizeof(double));

                        for(i=-center; i<center; i++)
                        {
                                sum=0.0f;
                                for (k=-128;k<128;k++)
                                {
                                        if ((k-i) % 2)
                                        {
                                                if      (k!=0)
                                                        sum+=(-4.0f/(NSP_PI*(k-i)))*
                                                                (((sin(NSP_PI*freq2*k)-sin(NSP_PI*freq1*k))/(NSP_PI*k)));
                                                else 
                                                        sum+=(-4.0f/(NSP_PI*(k-i)))*((freq2-freq1));
                                        }
                                };
                                FFirTab[center+i] =sum;
                        }
/*
        // NORMALISATION:
        // 1)calcule la Norme L1 du filtre:
        sum=0;
        for(i=0; i<nb_coef; i++)        sum+=fabs(FFirTab[i]);
        // 2) On doit avoir : Norme(Filtre)*Max(Sample:32000)<Max(Resultat de la convolution:65000*32000):
//      facteur = 65536.0 / sum;
        facteur = 1.0 / sum;
        for(i=0; i<nb_coef; i++)        coefs[i]=(float)(FFirTab[i]*facteur);
    */
    for (i=0;i<nb_coef;i++) coefs[i]=(float)FFirTab[i];

   SND_fn_vFreeSnd(FFirTab);



   //conversion au format spécifique Pentium
   for (i=0;i<nb_coef/4-1;i++)
            {
                coefs[i*4]=(coefs[i*4]/coefs[i*4+4]);
                coefs[i*4+1]=(coefs[i*4+1]/coefs[i*4+4+1]);
                coefs[i*4+2]=(coefs[i*4+2]/coefs[i*4+4+2]);
                coefs[i*4+3]=(coefs[i*4+3]/coefs[i*4+4+3]);
            }

            /*pour rendre le filtre inopérant
            for (i=0;i<nb_coef-1;i++)
                coefs[i]=(float)0.0;

            coefs[0]=1.0;
            coefs[nb_coef-1]=1.0;
            */
            
}
#endif //FILTRE_SURROUND

/*----------------------------------------------------------------------
    Inits spécifiques au Surround
----------------------------------------------------------------------*/
void InitSurround(void)
{
#ifdef FILTRE_SURROUND
    //DataBufferSurroundBrut=tableau où est fait le mix de la voie surround
    //taille en long=(taille_buffer/4)+TAILLE_FILTRE+1
    //  soit nb d'ech.+rabe pour le filtre qui nécessite les TAILLE_FILTRE ech précedent
    //      +1 rabe pour l'écriture en double qui écrit 2 longs (1 double) à chaque fois
        DataBufferSurroundBrut=(void*)SND_fn_pvMallocSnd(taille_buffer+4*TAILLE_FILTRE+4);
        memset(DataBufferSurroundBrut,0,taille_buffer+4*TAILLE_FILTRE);
    //DataBufferSurround=tableau où est stocké la voie surround avant mixe avec les voies stereo
    //taille en long=taille_buffer/4 soit le nb d'ech
        DataBufferSurround=(void*)SND_fn_pvMallocSnd(taille_buffer);
        memset(DataBufferSurround,0,taille_buffer);

        //GenerateFilter(Filtre,TAILLE_FILTRE,BANDPASS/*BAND_AND_PHASE*/,FREQ_OUTPUT);
        GenerateFilterFloat(FiltreFloat,TAILLE_FILTRE,FREQ_OUTPUT);
            //nspwFirInit(Filtre,TAILLE_FILTRE, NULL, &FilterState);
#else //FILTRE_SURROUND
        DataBufferSurroundBrut=(void*)SND_fn_pvMallocSnd(taille_buffer+OFFSET_SURROUND*4);
        memset(DataBufferSurroundBrut,0,taille_buffer+OFFSET_SURROUND*4);
#endif //FILTRE_SURROUND
}
/*----------------------------------------------------------------------
    Desinits spécifiques au Surround
----------------------------------------------------------------------*/
void DesInitSurround(void)
{
                SND_fn_vFreeSnd(DataBufferSurroundBrut);
#ifdef FILTRE_SURROUND
                SND_fn_vFreeSnd(DataBufferSurround);
#endif //FILTRE_SURROUND                
}

#ifdef FILTRE_SURROUND
#ifdef CODE_ASM_INLINE
void obsolete Mon_Filtre_Rapide(float* coefs,float* data_in,long* data_out,int nb_octets)
{
/*    long tmp;
    long* pl_adr=data_out;
    float* pf_adr,*pf_adr_init;
    float* coef;
    float tot;
    int i,j;
    */
    long DECAL[2]={0x00000000,0x43380000};

    _asm {
        pushad

        fsave   dword ptr [pile_fpu]
        finit

        //---
        fld     qword ptr [DECAL]
        mov     edx,dword ptr [nb_octets]
        mov     esi,dword ptr [data_in]
        mov     eax,dword ptr [coefs]
        mov     edi,dword ptr [data_out]
        sub     edx,TAILLE_FILTRE

        mov     ecx,0   ;TAILLE_FILTRE
        mov     ebx,esi
                                                ;0   1   2   3   4   5   6
boucle_1:
        fld     dword ptr [ebx]                 ;x0  D
        fmul    dword ptr [eax]                 ;cx0  D

        fld     dword ptr [ebx+8]               ;x2  cx0  D

        fld     dword ptr [ebx+4]               ;x1  x2  cx0  D
        fmul    dword ptr [eax+4]               ;cx1  x2  cx0  D

        fld     dword ptr [ebx+12]              ;x3  cx1  x2  cx0  D
        fxch    ST(3)                           ;cx0 cx1  x2  x3  D
        
boucle_2:
        fadd    dword ptr [ebx+ecx+16]          ;cx0+ cx1 x2 x3 D
        fxch    ST(2)                           ;x2 cx1 cx0+ x3 D

        fmul    dword ptr [eax+ecx+8]           ;cx2 cx1 cx0+ x3 D
        fxch    ST(1)                           ;cx1 cx2 cx0+ x3 D

        fadd    dword ptr [ebx+ecx+20]          ;cx1+ cx2 cx0+ x3 D   
        fxch    ST(3)                           ;x3 cx2 cx0+ cx1+ D

        fmul    dword ptr [eax+ecx+12]          ;cx3 cx2 cx0+ cx1+ D   
        fxch    ST(1)                           ;cx2 cx3 cx0+ cx1+ D

        fadd    dword ptr [ebx+ecx+24]          ;cx2+ cx3 cx0+ cx1+ D
        fxch    ST(2)                           ;cx0+ cx3 cx2+ cx1+ D

        fmul    dword ptr [eax+ecx+16]          ;cX4 cx3 cx2+ cx1+ D
        fxch    ST(1)                           ;cx3 cX4 cx2+ cx1+ D

        fadd    dword ptr [ebx+ecx+28]          ;cx3+ cX4 cx2+ cx1+ D
        fxch    ST(3)                           ;cx1+ cX4 cx2+ cx3+ D

        fmul    dword ptr [eax+ecx+20]          ;cX5 cX4 cx2+ cx3+ D
        fxch    ST(1)                           ;cX4 cX5 cx2+ cx3+ D

        add     ecx,16

        cmp     ecx,(TAILLE_FILTRE-4)*4
        jl      boucle_2

fin_boucle_2:
        fxch    ST(2)                           ;cx2+ cX5 cX4 cx3+

        fmul    dword ptr [eax+ecx+8]          ;cX6 cX5 cX4 cx3+ D
        fxch    ST(2)                           ;cX4 cX5 cX6 cx3+ D

        fadd    ST(0),ST(4)                     ;cX4+D cX5 cX6 cx3+ D
        fxch    ST(3)                           ;cx3+ cX5 cX6 cX4+D D
                                                          
        fmul    dword ptr [eax+ecx+12]          ;cX7 cX5  cX6 cX4+D D
        fxch    ST(2)                           ;cX6 cX5  cX7 cX4+D D

        faddp   ST(1),ST(0)                     ;cX6+5 cX7 cX4+D D
        fxch    ST(2)                           ;cX4+D cX7 cX6+5 D

        faddp   ST(1),ST(0)                     ;cX4+7+D cX6+5 D

        mov     eax,dword ptr [coefs]
        mov     ecx,0   ;TAILLE_FILTRE
        
        add     esi,4
        add     edi,4

        faddp   ST(1),ST(0)                     ;tot D

        dec     edx        
                                                ;0   1   2   3   4   5   6
        mov     ebx,[edi-4]
        fstp    qword ptr [edi-8]               ;D
        mov     [edi-4],ebx
        mov     ebx,esi

        cmp     edx,0             
        jne     boucle_1



        //---

        frstor  dword ptr [pile_fpu]

        popad
    }
/*
    _asm {
        pushad

        fsave   dword ptr [pile_fpu]
        finit

        //---
        fld     dword ptr [DECAL]
        mov     edx,dword ptr [nb_octets]
        mov     esi,dword ptr [data_in]
        mov     eax,dword ptr [coefs]
        mov     edi,dword ptr [data_out]
boucle_1:
        mov     ecx,TAILLE_FILTRE
        mov     ebx,esi
                                                ;0   1   2   3   4   5   6
        fld     dword ptr [eax]                 ;c0  D
        add     eax,4
        fmul    dword ptr [ebx]                 ;t   T
        add     ebx,4
        dec     ecx
        
boucle_2:
        fld     dword ptr [eax]                 ;c2  t   T   
        fmul    dword ptr [ebx]                 ;tt  t   T   
        fxch    ST(2)                           ;T   t   tt  
        faddp   ST(1),ST(0)                     ;T   tt  
        add     eax,4
        add     ebx,4
        dec     ecx

        cmp     ecx,0
        jne     boucle_2

        fld     dword ptr [DECAL]               ;D   T   tt
        fxch    ST(2)                           ;tt  T   D

        faddp   ST(1),ST(0)                     ;T   D

        mov     eax,dword ptr [coefs]
        dec     edx
        
        fstp    dword ptr [edi]                 ;D
        add     esi,4
        add     edi,4

        cmp     edx,0             
        jne     boucle_1



        //---

        frstor  dword ptr [pile_fpu]

        popad
    }
 */
    return;
    /*
    for (i=nb_octets,pl_adr=data_out,pf_adr_init=data_in;i>0;i--,pl_adr++,pf_adr_init++)
    {
        tot=0.0;
        for (j=TAILLE_FILTRE,pf_adr=pf_adr_init,coef=coefs;j>0;j--,coef++,pf_adr++)
        {
            tot+=(*coef)*(*pf_adr);
        }
        *pl_adr=(long)tot>>16;
    }
    */
}
#else //CODE_ASM_INLINE
extern "C"
{
        void __cdecl Mon_Filtre_Rapide_(float*,float*,long *,int);
        void __cdecl long_to_float_(long*,int);
}
#define Mon_Filtre_Rapide       Mon_Filtre_Rapide_
#define long_to_float           long_to_float_
#endif  //CODE_ASM_INLINE
#endif //FILTRE_SURROUND

#else //SURROUND
#pragma message("sans DolbySurround")
#endif //SURROUND

/*------------------------------------------------------------------
                                Antiparasitage lors du changement brusque de sample dans
                                la gestion du split pour le bruitage du moteur
                                (travail sur le buffer de sortie (tableau de short)
                                Entrée: néant
                                Sortie: néant
                                Appelé depuis le menu principal
-------------------------------------------------------------------*/
/*
void AntiParasite(void * adr,unsigned long nb_octets,long SeuilParasite)
{
        long * ptrtstgauche;
        long * ptrtstdroite;
        long * ptrtstprecgauche;
        long * ptrtstprecdroite;
        unsigned long nb_samples_to_recalc,i;
        short offset_correction,offset_correction_total;
        short nb_decalages,delta;

        int type = ANTI_PARASITAGE_PONDERE;

        if (adr != DataBufferInt)
        {
                ptrtstprecgauche = (long *)((int)adr-8);
                ptrtstprecdroite = (long *)((int)adr-4);
        }
        else
        {
                ptrtstprecgauche = (long *)((int)DataBufferInt+2*taille_buffer-8);
                ptrtstprecdroite = (long *)((int)DataBufferInt+2*taille_buffer-4);
        }

        ptrtstgauche = (long *)adr;
        ptrtstdroite = (long *)((int)adr+4);

        delta = (short)labs((int)(*ptrtstprecgauche-*ptrtstgauche));

// on ne descend pas trop bas en seuil de volume parasite
        if (SeuilParasite < SEUIL_PARASITE/16)
                SeuilParasite = SEUIL_PARASITE/16;

        if (delta > SeuilParasite)
        {
                nb_samples_to_recalc = 32;//128;//256;
                nb_decalages = 5;

                reessaye0:

                if (nb_decalages)
                {
                        if (nb_octets > nb_samples_to_recalc*4)
                        {
                                switch (type)
                                {
                                case ANTI_PARASITAGE_PONDERE :
                                        for (i=1;i<nb_samples_to_recalc;i++)
                                        {
                                                *ptrtstgauche = (long)(((int)(*ptrtstgauche*i) + (int)(*ptrtstprecgauche*(nb_samples_to_recalc-i))) >> nb_decalages);
                                                ptrtstgauche++;ptrtstgauche++;
                                        }
                                        break;

                                case ANTI_PARASITAGE_LINEAIRE :

                                        offset_correction = (short)(*(long *)((int)ptrtstgauche+nb_samples_to_recalc*4)-*ptrtstprecgauche);
                                        offset_correction >>= nb_decalages;
                                        offset_correction_total = offset_correction;
                                        for (i=1;i<nb_samples_to_recalc;i++)
                                        {
                                                *ptrtstgauche = *ptrtstprecgauche + offset_correction_total;
                                                offset_correction_total += offset_correction;
                                                ptrtstgauche++;ptrtstgauche++;
                                        }
                                        break;
                                }
                        }
                        else
                        {
                                nb_samples_to_recalc /= 2;
                                nb_decalages--;
                                goto reessaye0;
                        }
                }
        }

        delta = (short)labs((int)(*ptrtstprecdroite-*ptrtstdroite));

        if      (delta >  SeuilParasite)
        {
                nb_samples_to_recalc = 32;//256;
                nb_decalages = 5;

                reessaye1:

                if (nb_decalages)
                {
                        if (nb_octets > nb_samples_to_recalc*4)
                        {
                                switch (type)
                                {
                                case ANTI_PARASITAGE_PONDERE :
                                        for (i=1;i<nb_samples_to_recalc;i++)
                                        {
                                                *ptrtstdroite = (long)(((int)(*ptrtstdroite*i) + (int)(*ptrtstprecdroite*(nb_samples_to_recalc-i))) >> nb_decalages);
                                                ptrtstdroite++;ptrtstdroite++;
                                        }
                                        break;

                                case ANTI_PARASITAGE_LINEAIRE :
                                        offset_correction = (short)(*(long *)((int)ptrtstdroite+nb_samples_to_recalc*4)-*ptrtstprecdroite);
                                        offset_correction >>= nb_decalages;
                                        offset_correction_total = offset_correction;

                                        for (i=1;i<nb_samples_to_recalc;i++)
                                        {
                                                                        *ptrtstdroite = *ptrtstprecdroite + offset_correction_total;
                                                                        offset_correction_total += offset_correction;
                                                                        ptrtstdroite++;ptrtstdroite++;
                                        }
                                        break;
                                }
                        }
                        else
                        {
                                nb_samples_to_recalc /= 2;
                                nb_decalages--;
                                goto reessaye1;
                        }
                }
        }
}
*/


/*----------------------------------------------------------------------
                                Calcul de la suite du buffer
                                Entrées:adr=adresse cible
                nb_octets=nb d'octets à calculer
        Sortie:néant
        Appelé par SynchroSnd()
-----------------------------------------------------------------------*/
void genere_buffer(void* adr,unsigned long nb_octets)
{
    static BOOL deja_dedans=FALSE;

    if (!deja_dedans && nb_octets!=0)
    {
        deja_dedans=TRUE;

/*
        if (resol8)
        {//mix en 8 bits
            genere_buffer_8bits(adr,nb_octets);
        }
        else
*/
        {//mix en 16 bits
            genere_buffer_16bits(adr,nb_octets);
        }//mix 16 bits
        deja_dedans=FALSE;
    }//    if (!deja_dedans)
}
        
/*anciennes versions de genere_buffer
void genere_buffer(void* adr,unsigned long nb_octets)
{
    static BOOL deja_dedans=FALSE;

    unsigned char* pbAdr;
    unsigned char* pbAdrMax;
    unsigned char bTot;
    BUFFER_DISPO *buffer;

    char prev_dir[256];

                short wTot;
#ifndef NEW_MIX //vieux mix
        short* pwAdr;
                                short* pwAdrMax;
        short wTot_R,wTot_L;
        long lTot;
#else
#ifndef NEW_MIX_PLUS //ancien nouveau mix
        BOOL fin_mix;
        short* pwAdr;
        short* pwAdrMax;
        long lTot;
#else
#ifndef MIX_MULDEC
        //nouveau mix
        BOOL fin_mix;
                                short* pwAdr;
        short* pwAdrMax;
        //unsigned long ind_tampon_max;
                                short wTot_r;
                                long lTot;
                                DWORD err;
#else
#ifndef MIX_FLOAT
        //pseudo multiplication
        BOOL fin_mix;
        short* pwAdr;
        short* pwAdrMax;
        short wTot_r,wTot_l;
        int nd1,nd2,nd3,nd4,sd,sg;
        int nvol,npan;
        //long lTot;
#else
        short* pwAdrMax;
        short wTot_r,wTot;
        long lTot;
        char pile_fpu[108];
        float DECAL=3.0*pow(2,21);
        long sauve;
        short voieL,voieR;
#endif//MIX_FLOAT
#endif //mix_muldec
#endif //new_mix_plus
#endif //new_mix

    if (!deja_dedans)
    {
        deja_dedans=TRUE;

        if (resol8)
        {//mix en 8 bits
                pbAdr=(unsigned char*)adr;
        pbAdrMax=(unsigned char*)adr+nb_octets;
        bTot=0;
                                }
        else
        {//mix en 16 bits
#ifndef NEW_MIX //vieux mix
        pwAdr=(short*)adr;
        pwAdrMax=(short*)((long)adr+nb_octets);
                                do
        {
                                                                                                                                                                                                wTot_L=wTot_R=0;
            buffer=buffer_dispo_min;
            do
            {
                if (buffer->is_playing)
                {
                    if (buffer->pt_sign<buffer->pt_max)
                    {
                        lTot=(long)(*( (short*)buffer->pt_zero+(buffer->pt_sign>>OFFSET_BIT_INC) ) * buffer->vol);
                        wTot_R+=(lTot*buffer->pan)>>14;
                        wTot_L+=(lTot*(127-buffer->pan))>>14;
                        buffer->pt_sign+=buffer->inc_sign;
                    }
                    else
                    {
                        if (buffer->must_looping)
                        {
                            buffer->pt_sign=buffer->pt_loop;
                            lTot=(long)(*((short*)buffer->pt_zero + (buffer->pt_sign>>OFFSET_BIT_INC))*buffer->vol);
                            wTot_R+=(lTot*buffer->pan)>>14;
                            wTot_L+=(lTot*(127-buffer->pan))>>14;
                            buffer->pt_sign+=buffer->inc_sign;
                                                                                                }
                        else
                            buffer->is_playing=0;
                    }
                }
            } while ((++buffer)<buffer_dispo_max);

            *pwAdr=wTot_L;
            *(pwAdr+1)=wTot_R;
            pwAdr+=2;
        } while (pwAdr<pwAdrMax);
#else
#ifndef NEW_MIX_PLUS //ancien nouveau mix
        pwAdrMax=(short*)((long)adr+nb_octets);
        buffer=buffer_dispo_min;
        
        memset(adr,0,nb_octets);
                                do {
            if (buffer->is_playing)
                                                {
                pwAdr=(short*)adr;
                fin_mix=FALSE;
                do {
                    if (buffer->pt_sign<buffer->pt_max)
                    {
                        lTot=(long)(*( (short*)buffer->pt_zero + (buffer->pt_sign>>OFFSET_BIT_INC) )) * buffer->vol ;
                        (*(pwAdr++))+=(short)((lTot*(127-buffer->pan))>>14);
                        (*(pwAdr++))+=(short)((lTot*buffer->pan)>>14);
                        buffer->pt_sign+=buffer->inc_sign;
                    }
                    else
                    {
                        if (buffer->must_looping)
                        {
                            buffer->pt_sign=buffer->pt_loop;
                            lTot=(long)(*( (short*)buffer->pt_zero + (buffer->pt_sign>>OFFSET_BIT_INC) )) * buffer->vol ;
                            (*(pwAdr++))+=(short)((lTot*(127-buffer->pan))>>14);
                            (*(pwAdr++))+=(short)((lTot*buffer->pan)>>14);
                            buffer->pt_sign+=buffer->inc_sign;
                        }
                        else
                        {
                                                                                                                buffer->is_playing=0;
                            fin_mix=TRUE;
                        }
                    }
                } while ((pwAdr<pwAdrMax) && (!fin_mix));
            }
        } while ((++buffer)<buffer_dispo_max);
#else 
#ifndef MIX_MULDEC
        //nouveau mix
        pwAdrMax=(short*)((long)adr+nb_octets);
#ifdef OBSOLETE_STREAMING
                                buffer=&buffer_dispo_streaming;
        //init du contenu du buffer (contenu du streaming ou 0)
        if (buffer->is_playing)
        {
                                                GetCurrentDirectory(sizeof(prev_dir),prev_dir);
            if (!SetCurrentDirectory(DirectorySnd))
                                                                err=GetLastError();

            pwAdr=(short*)adr;
            fin_mix=FALSE;
            while (!fin_mix)
            {
                //calcule sample
                lTot=(long)(*((short*)buffer_tampon+(buffer->pt_sign>>OFFSET_BIT_INC)-ind_file_buffer_tampon))*buffer->vol;
                wTot_r=(short)((lTot*buffer->pan)>>14);
                (*(pwAdr++))=(lTot>>14)-wTot_r;
                (*(pwAdr++))=wTot_r;

                //raj buffer_dispo
                buffer->pt_sign+=buffer->inc_sign;

                if (buffer->pt_sign>=ind_file_buffer_tampon_max)
                {//raj tampon
                    ind_file_buffer_tampon+=TAILLE_BUFFER_TAMPON;
                    charge_data_in_mem(buffer_tampon
                        ,TAILLE_BUFFER_TAMPON
                        ,sounddescriptor[buffer->sample].init.fichier
                        ,sounddescriptor[buffer->sample].init.ptr+ind_file_buffer_tampon);
                    ind_file_buffer_tampon_max+=TAILLE_BUFFER_TAMPON<<OFFSET_BIT_INC;
                }

                if (buffer->pt_sign>=buffer->pt_max)
                {//on est à la fin du sample
                    if (buffer->must_looping)
                    {//le sample boucle
                        buffer->is_looping=TRUE;
                        buffer->pt_sign=buffer->pt_loop;
                        ind_file_buffer_tampon=sounddescriptor[buffer->sample].init.ptr+(buffer->pt_sign>>OFFSET_BIT_INC) & 0xFFFFFFFE;
                        charge_data_in_mem(buffer_tampon
                            ,TAILLE_BUFFER_TAMPON
                            ,sounddescriptor[buffer->sample].init.fichier
                            ,sounddescriptor[buffer->sample].init.ptr);
                                                                                                ind_file_buffer_tampon_max=TAILLE_BUFFER_TAMPON<<OFFSET_BIT_INC;
                    }
                    else
                                                                                {//stop le sample
                        buffer->is_playing=FALSE;
                                                                                                fin_mix=TRUE;
                    }
                }

                if (pwAdr>=pwAdrMax)
                {//fin du buffer
                    fin_mix=TRUE;
                }
            }//while !fin_mix
            SetCurrentDirectory(prev_dir);

            if (pwAdr<pwAdrMax)
            {//on n'a pas fini de remplir le buffer
                memset(pwAdr,0,pwAdrMax-pwAdr);
            }
        }//if buffer_streaming playing
        else//pas de streaming
#endif
        {
            memset(adr,0,nb_octets);
        }
        
        buffer=buffer_dispo_min;

#define VOL_MINI 3

        do {
            if ((buffer->is_playing) && (buffer->vol>VOL_MINI))
            {
                pwAdr=(short*)adr;
                fin_mix=FALSE;
                do {
                    if (buffer->pt_sign<buffer->pt_max)
                    {
                        wTot=*( (short*)buffer->pt_zero + (buffer->pt_sign>>OFFSET_BIT_INC) );
                        lTot=(long)(*( (short*)buffer->pt_zero + (buffer->pt_sign>>OFFSET_BIT_INC) )) * buffer->vol ;
                        wTot_r=(short)((lTot*buffer->pan)>>14);
                                                                                                (*(pwAdr++))+=(short)(lTot>>7)-wTot_r;
                        (*(pwAdr++))+=wTot_r;

                        buffer->pt_sign+=buffer->inc_sign;
                                                                                }
                    else
                                                                                {
                        if (buffer->must_looping)
                        {
                            buffer->pt_sign=buffer->pt_loop;
                        
                            lTot=(long)(*( (short*)buffer->pt_zero + (buffer->pt_sign>>OFFSET_BIT_INC) )) * buffer->vol ;
                            wTot_r=(short)((lTot*buffer->pan)>>14);
                            (*(pwAdr++))+=(lTot>>7)-wTot_r;
                            (*(pwAdr++))+=wTot_r;
                            
                            buffer->pt_sign+=buffer->inc_sign;
                        }
                        else
                        {
                            buffer->is_playing=0;
                            fin_mix=TRUE;
                        }
                    }
                } while ((pwAdr<pwAdrMax) && (!fin_mix));
            }
        } while ((++buffer)<buffer_dispo_max);
#else
#ifndef MIX_FLOAT
#pragma message("verifier les voies L-R (inversées ?)")
                                //pseudo multiplication
        pwAdrMax=(short*)((long)adr+nb_octets);
        buffer=buffer_dispo_min;
        
        memset(adr,0,nb_octets);
        do {
            if (buffer->is_playing)
            {
                pwAdr=(short*)adr;
                fin_mix=FALSE;

                nvol = CodedPanVol[buffer->vol];
                                                                                npan = CodedPanVol[buffer->pan];
                    nd1 = (nvol >> 24) & 0xFF;
                    nd2 = (nvol >> 16) & 0xFF;
                                                                nd3 = (npan >> 24) & 0xFF;
                nd4 = (npan >> 16) & 0xFF;

                if (nvol&0x1)
                {
                    if (npan&0x1)
                    {
                      _asm {
                        pushad

                        //durant la boucle:
                        //edx contient l'adresse de buffer
                        //edi l'adresse du prochain sample à générer
                        //eci la valeur maxi de edi
                        //ebx contient la valeur de pt_sign

                        //eax et ebp libres

                        mov     esi,dword ptr [pwAdrMax]//esi=*pwAdrMax
                        //mov     eax,sar1
                        mov     ebx,nd1
                        mov     byte ptr [sar1_1+2],bl
                        mov     ebx,nd2
                        mov     byte ptr [sar1_1+5],bl
                        //mov     eax,sar2
                        mov     ebx,nd3
                        mov     byte ptr [sar2_1+2],bl
                                                                                                mov     ebx,nd4
                        mov     byte ptr [sar2_1+5],bl
                        //((char*)sar1+2)=nd1;
                //*((char*)sar1+5)=nd2;
                //*((char*)sar2+2)=nd3;
                //*((char*)sar2+5)=nd4;
                        mov     edi,dword ptr [adr]     //edi=*adr

                        mov     edx,dword ptr [buffer]  //edx=*buffer=buffer->pt_sign
                        mov     ebx,[edx]               //ebx=*(buffer->pt_sign)

    debut_looping_1:      //debut de la boucle
                                                                                                cmp     ebx,[edx+8]
                        jae     fin_sample_1        //si !(*(buffer->pt_sign)<*(buffer->pt_max)) goto fin_sample

    calc_sample_1:        //il faut calculer le sample
                                                                                                push    ebx
                        mov     eax,ebx
                        shr     eax,OFFSET_BIT_INC-1
                        and     eax,0xFFFFFFFE
                        add     eax,[edx+16]    //eax=buffer->pt_sign>>OFFSET + buffer->pt_zero=sample
                
                        movsx   ecx,word ptr [eax]       //ecx=sample
                        mov     ebx,ecx
sar1_1:
                        sar     ecx,0
                        sar     ebx,0
                        add     ecx,ebx         //ecx=sample*vol
                        mov     ebx,ecx         //ebx=copie de ecx
                        mov     eax,ecx         //eax=s
sar2_1:
                        sar     ecx,0
                        sar     ebx,0
                        add     ecx,ebx         //ecx=sd

                        add     word ptr [edi],cx
                        sub     eax,ecx         //eax=sg
                        add     word ptr [edi+2],ax

                        pop     ebx

                        add     edi,4                 //edi+=4
                                                                                                add     ebx,[edx+4]         //buffer->pt_sign+=inc_sign
                        jmp     do_looping_1      //next sample

    fin_sample_1:         //on est à la fin du sample
                        test    [edx+40],0xFFFFFFFF
                        je      dead_voice_1  //si !(*buffer->must_looping) goto dead_voice

                        //le sample doit boucler
                        mov     ebx,[edx+12]   //ebx<-buffer->loop
                        jmp     calc_sample_1 //on reboucle

    dead_voice_1:         //la voie est arrêtée
                        mov     [edx+44],0  //*buffer->is_playing=0
                                                                                                jmp     fin_looping_1

                do_looping_1:         //next sample
                        cmp     esi,edi
                        ja      debut_looping_1
                        //si (pwAdr<pwAdrMax) goto calc_sample else goto fin_looping

    fin_looping_1:        //fin de la loop
                        mov     [edx],ebx       //restauration de pt_sign

                        popad
                    }//-asm
                    }
                    else    //pan & 0X01
                    {
                      _asm {
                        pushad

                        //durant la boucle:
                        //edx contient l'adresse de buffer
                        //edi l'adresse du prochain sample à générer
                        //eci la valeur maxi de edi
                        //ebx contient la valeur de pt_sign

                        //eax et ebp libres

                        mov     esi,dword ptr [pwAdrMax]//esi=*pwAdrMax
                        //mov     eax,sar1
                        mov     ebx,nd1
                                                                                                mov     byte ptr [sar1_2+2],bl
                        mov     ebx,nd2
                        mov     byte ptr [sar1_2+5],bl
                        //mov     eax,sar2
                        mov     ebx,nd3
                        mov     byte ptr [sar2_2+2],bl
                        mov     ebx,nd4
                        mov     byte ptr [sar2_2+5],bl
                        //((char*)sar1+2)=nd1;
                //*((char*)sar1+5)=nd2;
                //*((char*)sar2+2)=nd3;
                //*((char*)sar2+5)=nd4;
                                                                                                mov     edi,dword ptr [adr]     //edi=*adr

                                                                                                mov     edx,dword ptr [buffer]  //edx=*buffer=buffer->pt_sign
                        mov     ebx,[edx]               //ebx=*(buffer->pt_sign)

    debut_looping_2:      //debut de la boucle
                        cmp     ebx,[edx+8]
                        jae     fin_sample_2        //si !(*(buffer->pt_sign)<*(buffer->pt_max)) goto fin_sample

    calc_sample_2:        //il faut calculer le sample

                        push    ebx

                        mov     eax,ebx
                        shr     eax,OFFSET_BIT_INC-1
                        and     eax,0xFFFFFFFE
                        add     eax,[edx+16]    //eax=buffer->pt_sign>>OFFSET + buffer->pt_zero=sample
                
                        movsx   ecx,word ptr [eax]       //ecx=sample
                        mov     ebx,ecx
sar1_2:
                        sar     ecx,0
                        sar     ebx,0
                        add     ecx,ebx         //ecx=sample*vol
                        mov     ebx,ecx         //ebx=copie de ecx
                        mov     eax,ecx         //eax=s

sar2_2:
                        sar     ecx,0
                        sar     ebx,0
                                                                                                add     ecx,ebx         //ecx=sd

                        add     word ptr [edi+2],cx
                        sub     eax,ecx         //eax=sg
                        add     word ptr [edi],ax

                        pop     ebx

                        add     edi,4                 //edi+=4

                        add     ebx,[edx+4]         //buffer->pt_sign+=inc_sign

                        jmp     do_looping_2      //next sample

    fin_sample_2:         //on est à la fin du sample
                        test    [edx+40],0xFFFFFFFF
                        je      dead_voice_2  //si !(*buffer->must_looping) goto dead_voice

                        //le sample doit boucler
                        mov     ebx,[edx+12]
                        jmp     calc_sample_2 //on reboucle

    dead_voice_2:         //la voie est arrêtée
                        mov     [edx+44],0  //*buffer->is_playing=0
                        jmp     fin_looping_2

    do_looping_2:         //next sample
                        cmp     esi,edi
                        ja      debut_looping_2
                        //si (pwAdr<pwAdrMax) goto calc_sample else goto fin_looping

    fin_looping_2:        //fin de la loop
                        mov     [edx],ebx       //restauration de pt_sign

                        popad
                    }//-asm
                    }
                }
                else    // else du volume & 1
                    if (npan&0x1)
                    {
                        _asm {
                                                                                                pushad

                        //durant la boucle:
                        //edx contient l'adresse de buffer
                        //edi l'adresse du prochain sample à générer
                        //eci la valeur maxi de edi
                        //ebx contient la valeur de pt_sign

                        //eax et ebp libres

                                                                                                mov     esi,dword ptr [pwAdrMax]//esi=*pwAdrMax
                        //mov     eax,sar1
                                                                                                mov     ebx,nd1
                        mov     byte ptr [sar1_3+2],bl
                        mov     ebx,nd2
                        mov     byte ptr [sar1_3+5],bl
                                                                                                //mov     eax,sar2
                        mov     ebx,nd3
                        mov     byte ptr [sar2_3+2],bl
                        mov     ebx,nd4
                        mov     byte ptr [sar2_3+5],bl
                        //(char*)sar1+2)=nd1;
                //*((char*)sar1+5)=nd2;
                //*((char*)sar2+2)=nd3;
                //*((char*)sar2+5)=nd4;
                        mov     edi,dword ptr [adr]     //edi=*adr

                        mov     edx,dword ptr [buffer]  //edx=*buffer=buffer->pt_sign
                        mov     ebx,[edx]               //ebx=*(buffer->pt_sign)

    debut_looping_3:      //debut de la boucle
                        cmp     ebx,[edx+8]
                        jae     fin_sample_3        //si !(*(buffer->pt_sign)<*(buffer->pt_max)) goto fin_sample

    calc_sample_3:        //il faut calculer le sample

                        push    ebx

                        mov     eax,ebx
                        shr     eax,OFFSET_BIT_INC-1
                        and     eax,0xFFFFFFFE
                        add     eax,[edx+16]    //eax=buffer->pt_sign>>OFFSET + buffer->pt_zero=sample

                        movsx   ecx,word ptr [eax]       //ecx=sample
                        mov     ebx,ecx
                        mov     eax,ecx
sar1_3:
                        sar     ecx,0
                        sar     ebx,0
                        sub     eax,ecx
                        sub     eax,ebx     //eax=s

                        mov     ebx,eax         //ebx=copie de eax
                                                                                                mov     ecx,eax         //eax=copi de eax

sar2_3:
                        sar     ecx,0
                                                                                                sar     ebx,0
                        add     ecx,ebx         //ecx=sd

                        add     word ptr [edi],cx
                        sub     eax,ecx         //eax=sg
                        add     word ptr [edi+2],ax

                        pop     ebx

                        add     edi,4                 //edi+=4

                        add     ebx,[edx+4]         //buffer->pt_sign+=inc_sign

                        jmp     do_looping_3      //next sample

    fin_sample_3:         //on est à la fin du sample
                        test    [edx+40],0xFFFFFFFF
                        je      dead_voice_3  //si !(*buffer->must_looping) goto dead_voice

                        //le sample doit boucler
                        mov     ebx,[edx+12]
                        jmp     calc_sample_3 //on reboucle

    dead_voice_3:         //la voie est arrêtée
                        mov     [edx+44],0  //*buffer->is_playing=0
                        jmp     fin_looping_3

                do_looping_3:         //next sample
                        cmp     esi,edi
                        ja      debut_looping_3
                        //si (pwAdr<pwAdrMax) goto calc_sample else goto fin_looping

    fin_looping_3:        //fin de la loop
                        mov     [edx],ebx       //restauration de pt_sign

                                                                                                popad
                    }//-asm
                                                                                }
                    else
                    {
                      _asm {
                                                                                                pushad

                        //durant la boucle:
                        //edx contient l'adresse de buffer
                        //edi l'adresse du prochain sample à générer
                                                                                                //eci la valeur maxi de edi
                        //ebx contient la valeur de pt_sign

                        //eax et ebp libres

                        mov     esi,dword ptr [pwAdrMax]//esi=*pwAdrMax
                        //mov     eax,sar1
                        mov     ebx,nd1
                        mov     byte ptr [sar1_4+2],bl
                        mov     ebx,nd2
                        mov     byte ptr [sar1_4+5],bl
                        //mov     eax,sar2
                        mov     ebx,nd3
                        mov     byte ptr [sar2_4+2],bl
                        mov     ebx,nd4
                        mov     byte ptr [sar2_4+5],bl
                        //*((char*)sar1+2)=nd1;
                //*((char*)sar1+5)=nd2;
                //*((char*)sar2+2)=nd3;
                //*((char*)sar2+5)=nd4;
                        mov     edi,dword ptr [adr]     //edi=*adr

                        mov     edx,dword ptr [buffer]  //edx=*buffer=buffer->pt_sign
                                                                                                mov     ebx,[edx]               //ebx=*(buffer->pt_sign)

    debut_looping_4:      //debut de la boucle
                        cmp     ebx,[edx+8]
                        jae     fin_sample_4        //si !(*(buffer->pt_sign)<*(buffer->pt_max)) goto fin_sample

    calc_sample_4:        //il faut calculer le sample

                        push    ebx

                        mov     eax,ebx
                        shr     eax,OFFSET_BIT_INC-1
                        and     eax,0xFFFFFFFE
                                                                                                add     eax,[edx+16]    //eax=buffer->pt_sign>>OFFSET + buffer->pt_zero=sample
                
                        movsx   ecx,word ptr [eax]       //ecx=sample
                        mov     ebx,ecx
                        mov     eax,ecx
sar1_4:
                        sar     ecx,0
                        sar     ebx,0
                        sub     eax,ecx
                        sub     eax,ebx         //eax=s
                        mov     ebx,eax         //ebx=copie de eax
                        mov     ecx,eax         //ecx=copie de eax

sar2_4:
                        sar     ecx,0
                        sar     ebx,0
                        add     ecx,ebx         //ecx=sd

                        add     word ptr [edi+2],cx
                        sub     eax,ecx         //eax=sg
                        add     word ptr [edi],ax

                        pop     ebx

                        add     edi,4                 //edi+=4

                        add     ebx,[edx+4]         //buffer->pt_sign+=inc_sign

                        jmp     do_looping_4      //next sample

    fin_sample_4:         //on est à la fin du sample
                        test    [edx+40],0xFFFFFFFF
                        je      dead_voice_4  //si !(*buffer->must_looping) goto dead_voice

                        //le sample doit boucler
                                                                                                mov     ebx,[edx+12]
                        jmp     calc_sample_4 //on reboucle

    dead_voice_4:         //la voie est arrêtée
                        mov     [edx+44],0  //*buffer->is_playing=0
                        jmp     fin_looping_4

    do_looping_4:         //next sample
                        cmp     esi,edi
                        ja      debut_looping_4
                        //si (pwAdr<pwAdrMax) goto calc_sample else goto fin_looping

    fin_looping_4:        //fin de la loop
                        mov     [edx],ebx       //restauration de pt_sign

                        popad
                    }//-asm
                    }




            }
        } while ((++buffer)<buffer_dispo_max);
#else
#pragma message("verifier les voies L-R (inversées ?)")
        pwAdrMax=(short*)((long)adr+nb_octets);
        buffer=buffer_dispo_min;
        
        memset(adr,0,nb_octets);
        do {
            if (buffer->is_playing)
            {
                
                //1° méthode: parcourt des samples voie/voie
                _asm {
                                                                                pushad

                    fsave   dword ptr [pile_fpu]
                    finit 

                                                                                //durant la boucle:
                    //edx contient l'adresse de buffer
                                                                                //edi l'adresse du prochain sample à générer
                    //eci la valeur maxi de edi
                    //ebx contient la valeur de pt_sign

                                                                                //eax et ebp libres

                    mov     edi,dword ptr [adr]     //edi=*adr

                    mov     esi,dword ptr [buffer]  //edx=*buffer=buffer->pt_sign
                                                                                mov     ebx,[esi]               //ebx=*(buffer->pt_sign)

                    fld     dword ptr [DECAL]
                    fld     dword ptr [esi+56]  //ST=a
                    fld     dword ptr [esi+60]  //ST=b
                    fld     dword ptr [esi+56]  //ST=a
                    fld     dword ptr [esi+60]  //ST=b
                                                //&t  X   sig X   buf
                    mov     eax,ebx              
                    mov     ecx,[esi+16]  
                    shr     eax,OFFSET_BIT_INC-1
                    and     eax,0xFFFFFFFE
                    add     ecx,eax
                    //suivi de ST                 edi eax ebx ecx esi 0   1   2   3   4   5   6
                    //                            &t  X   sig &s  buf b   a   b   a   DECAL
debut_looping:      //debut de la boucle
                    cmp     ebx,[esi+8]         //        +       +
                    jae     fin_sample        //si !(*(buffer->pt_sign)<*(buffer->pt_max)) goto fin_sample

calc_sample:        //il faut calculer le sample
                    //suivi de ST                 edi eax ebx ecx esi 0   1   2   3   4   5   6
                                                //&t  X   sig &s  buf s   b   a   b   a   DECAL
                    fild    word ptr [ecx]      //            +
                    add     ebx,[esi+4]         //        sig      +
                    add     edi,4               //&t'
                    fmul    ST(1),ST(0)         //                    s   sb  a   b   a   DECAL
                                                                                mov     edx,ebx             //        sig
                    mov     ecx,[esi+16]        //            zer  +
                    fmulp   ST(2),ST(0)         //                    sa  sb  b   a   DECAL
                    mov     eax,[edi]           //    t
                                                                                fadd    ST(0),ST(4)         //                    sb+ sa  b   a   DECAL
                    shr     edx,OFFSET_BIT_INC-1//    si
                                                                                and     edx,0xFFFFFFFE      //    si
                    fstp    word ptr [voieR]    //                    sa  b   a   DECAL
                    fadd    ST(0),ST(3)         //                    sa+ b   a   DECAL
                    add     ax,word ptr [voieR] //    t       
                                                                                fstp    word ptr [voieL]    //                    b   a   DECAL
                    ror     eax,16              //    t        
                    fld     ST(1)               //                    a   b   a   DECAL
                    add     ax,word ptr [voieL] //    t  
                    ror     eax,16              //    t
                                                                                fld     ST(1)               //                    b   a   b   a   DECAL
                    mov     [edi],eax           //+   +
                    add     ecx,edx             //    +       &s'
                    
                    jmp     do_looping      //next sample

fin_sample:         //on est à la fin du sample
                    test    [esi+40],0xFFFFFFFF
                    je      dead_voice  //si !(*buffer->must_looping) goto dead_voice

                    //le sample doit boucler
                    mov     ebx,[esi+24]
                    jmp     calc_sample //on reboucle

dead_voice:         //la voie est arrêtée
                    mov     [esi+44],0  //*buffer->is_playing=0
                    jmp     fin_looping

do_looping:         //next sample
                    cmp     dword ptr [pwAdrMax],edi
                    ja      debut_looping
                    //si (pwAdr<pwAdrMax) goto calc_sample else goto fin_looping

fin_looping:        //fin de la loop
                    mov     [esi],ebx       //restauration de pt_sign

                    frstor  dword ptr [pile_fpu]

                    popad
                }//-asm
                                                                //sprintf(texte,"pt_sign %d",buffer->pt_sign);
                                                                //MessageBox(HWND_DESKTOP,texte,"coucou",MB_OK);
                                                }//if is_playing
                                } while ((++buffer)<buffer_dispo_max);
#endif//MIX_FLOAT
#endif //mix_muldec
#endif //new_mix_plus
#endif //new_mix
                }//resol8

#ifdef TRAVAIL
                char texte[80];

                sprintf(texte,"%x",buffer_dispo[0].is_playing);
                SetDlgItemText(hwndSupervisatermix,IDC_ACT1,texte);
                sprintf(texte,"%x",buffer_dispo[0].pt_sign);
                SetDlgItemText(hwndSupervisatermix,IDC_PT1,texte);
                sprintf(texte,"%x",buffer_dispo[0].inc_sign);
                SetDlgItemText(hwndSupervisatermix,IDC_INC1,texte);
                sprintf(texte,"%x",buffer_dispo[1].is_playing);
                SetDlgItemText(hwndSupervisatermix,IDC_ACT2,texte);
                sprintf(texte,"%x",buffer_dispo[1].pt_sign);
    SetDlgItemText(hwndSupervisatermix,IDC_PT2,texte);
    sprintf(texte,"%x",buffer_dispo[1].inc_sign);
    SetDlgItemText(hwndSupervisatermix,IDC_INC2,texte);
#endif

    deja_dedans=FALSE;
}
}
*/

/****************************************************************
PLAYSND(,,,)=lancement du son
                                Entrées:num_sample:désignation du sample cf sounddescriptor[num_sample]
                        par             :paramètres au lancement(vol,pan...)
                        prio    :niveau de priorité(0=faible à +X=élevée)
                        fct             :fonction à appeler lorsque le son sera stoppé(naturellement ou artificiellement)
        Retour: indice désignant la voie physique (suivis dynamique)
                                                                                                ECHEC_PLAYSND si échec
                Appelé par SOUND3D pour jouer un sample
*****************************************************************/
/*
long PlaySnd(long num_sample,SOUNDPARAM* par,long prio,SOUNDCALLBACK fct)
{
        prio=prio;
#ifdef HARDSND
    int indice;
#ifdef SUPERVISATER
                SUPERVISATER_INFO super_info;
#endif
    int i;

    snd_assert(num_sample<nb_sound);snd_assert(num_sample>=0);

    snd_dump("Play %d:",num_sample);//snd_dump("[recu à %d]\n",timeGetTime());

#ifdef OBSOLETE_STREAMING
    if ((sounddescriptor[num_sample].streaming) && (sounddescriptor[num_sample].init.dispo))
    {
        if (buffer_dispo_streaming.is_playing)
            StopSnd(VOICE_STREAMING);

        ind_file_buffer_tampon=0;
        ind_file_buffer_tampon_max=TAILLE_BUFFER_TAMPON<<OFFSET_BIT_INC;

        //le buffer utilisé est buffer_dispo_streaming!
        snd_dump("(buffer_dispo_streaming)",0);

        //buffer_dispo_streaming.pt_zero=0;//non significatif pour le streaming
        buffer_dispo_streaming.pt_sign=0;

        if (sounddescriptor[num_sample].looping)
            buffer_dispo_streaming.pt_max=min(sounddescriptor[num_sample].init.size<<OFFSET_BIT_INC,
                (sounddescriptor[num_sample].init.start_loop+sounddescriptor[num_sample].init.size_loop)<<OFFSET_BIT_INC);
        else
                                                buffer_dispo_streaming.pt_max=sounddescriptor[num_sample].init.size<<OFFSET_BIT_INC;

        buffer_dispo_streaming.pt_loop=sounddescriptor[num_sample].init.start_loop<<OFFSET_BIT_INC;
        buffer_dispo_streaming.sample=num_sample;
        buffer_dispo_streaming.must_looping=sounddescriptor[num_sample].looping;
                                buffer_dispo_streaming.is_looping=FALSE;
        buffer_dispo_streaming.waiting_callback=FALSE;

        //le buffer à jouer est buffer_dispo_streaming
        snd_dump("(vol=%d-",volume_general_in_dB+vol_2_hth_dB((sounddescriptor[num_sample].volume0*(par->vol+1))>>7));
        snd_dump("%dHz)",(long)(par->freq*sounddescriptor[num_sample].freq0));
            
        buffer_dispo_streaming.vol=par->vol;

                                buffer_dispo_streaming.inc_sign=get_inc_for_voice(num_sample,par->freq);

        //init du buffer_dispo
        if (sounddescriptor[num_sample].init.res==16)
        {//le pas est *2 (pas en ech->pas en bytes)
                                                buffer_dispo_streaming.resol8=FALSE;
            buffer_dispo_streaming.pt_max>>=1;
            buffer_dispo_streaming.pt_loop>>=1;
        }
        else
            buffer_dispo_streaming.resol8=TRUE;

        if (stereo_active) 
            buffer_dispo_streaming.pan=par->pan;
        else
            buffer_dispo_streaming.pan=64;

#ifdef MIX_FLOAT
        buffer_dispo_streaming.a=(float)buffer_dispo_streaming.pan*buffer_dispo_streaming.vol/(127*127);
        buffer_dispo_streaming.b=(float)(127.0-buffer_dispo_streaming.pan)*buffer_dispo_streaming.vol/(127*127);
#endif

        buffer_dispo_streaming.is_playing=TRUE;

#ifdef SUPERVISATER
                                super_info.vol=par->vol;
                                super_info.freq=get_inc_for_voice(num_sample,par->freq);
                                SendMessage(hwndSupervisater,MSG_REFRESH_SUPERVISATER,VOICE_STREAMING,(LPARAM)&super_info);
#endif

                                if (fct!=NULL)
                                {//il y a un Callback
                                                snd_dump("wait séma Callback dans PlaySnd-",0);

                                                buffer_dispo_streaming.waiting_callback=TRUE;
                                                buffer_dispo_streaming.fct_callback=fct;
                                }
                                else
                                {//pas de Callback; peut-être looping ?
                                if (sounddescriptor[num_sample].looping)
                                                {//loopant
                                                                buffer_dispo_streaming.is_looping=TRUE;
                                                                snd_dump("wait séma Looping dans PlaySnd-",0);
                                                }
                                }//fct!=NULL

                                snd_dump("->%X\n",VOICE_STREAMING);
                                buffer_dispo_streaming.sample=num_sample;

                                return (VOICE_STREAMING);

                }
#endif//streaming

                if (sounddescriptor[num_sample].dispo)
                {//sample disponible
                                //recherche d'un buffer_dispo dispo
                                indice=0;
                                while (buffer_dispo[indice].is_playing) indice++;

                                i = 0;

                                while (i++ < NB_VOICE_MIXED_MAX)
                                {
                                                                if ((buffer_dispo[indice].is_playing)&&
                                                                                                (buffer_dispo[indice].is_mixing))
                                                                                                nb_samples_actifs ++;
                                }

                                if (indice==NB_VOICE_MIXED_MAX)
                                {
                                                                snd_dump("Plus de buffer_dispo!",0);
                                                                return ECHEC_PLAYSND;
                                }

                                                                                                                                //le buffer dispo est buffer_dispo[indice]
                                snd_dump("(buffer_dispo[%d])",indice);

                                buffer_dispo[indice].pt_zero=(unsigned long)sounddescriptor[num_sample].sample.data;
                                buffer_dispo[indice].pt_sign=0;

                                                                                                                                //MODIFOLI debut: calcul de pt_max modulo 8 octets pour MMX
                                if (sounddescriptor[num_sample].looping)
                                                buffer_dispo[indice].pt_max=min(sounddescriptor[num_sample].init.size<<OFFSET_BIT_INC,
                                                                (sounddescriptor[num_sample].init.start_loop+sounddescriptor[num_sample].init.size_loop)<<OFFSET_BIT_INC);
                                else
                                                buffer_dispo[indice].pt_max=sounddescriptor[num_sample].init.size<<OFFSET_BIT_INC;

                                buffer_dispo[indice].pt_loop=sounddescriptor[num_sample].init.start_loop<<OFFSET_BIT_INC;
                                buffer_dispo[indice].sample=num_sample;
                                buffer_dispo[indice].must_looping=sounddescriptor[num_sample].looping;
                                buffer_dispo[indice].is_looping=FALSE;
                                buffer_dispo[indice].waiting_callback=FALSE;


                                //le buffer à jouer est buffer_dispo[indice]
                                snd_dump("(vol=%d-",volume_general_in_dB+vol_2_hth_dB((sounddescriptor[num_sample].volume0*(par->vol+1))>>7));
                                snd_dump("%dHz)",(long)(par->freq*sounddescriptor[num_sample].freq0));

                                buffer_dispo[indice].vol=(par->vol*sounddescriptor[num_sample].volume0)>>7;

// si un quart des voies sont prises, on commence a filtrer les sons faibles
//              if (nb_samples_actifs > NB_VOICE_MIXED_MAX / 4)

//              if (buffer_dispo[indice].vol < SEUIL_VOLUME_MINI)
//                    buffer_dispo[indice].is_mixing = FALSE;
//      else
                                buffer_dispo[indice].is_mixing = TRUE;

                                buffer_dispo[indice].inc_sign=get_inc_for_voice(num_sample,par->freq);

                                //init du buffer_dispo
                                if (sounddescriptor[num_sample].init.res==16)
                                {//le pas est *2 (pas en ech->pas en bytes)
                                                buffer_dispo[indice].resol8=FALSE;
                                                buffer_dispo[indice].pt_max>>=1;
                                                buffer_dispo[indice].pt_loop>>=1;
                                                                                                                                }
                                else
                                                                buffer_dispo[indice].resol8=TRUE;

                                if (stereo_active)
                buffer_dispo[indice].pan=par->pan;
                                else
                                                                buffer_dispo[indice].pan=64;

#ifdef MIX_FLOAT
        buffer_dispo[indice].a=(float)buffer_dispo[indice].pan*buffer_dispo[indice].vol/(127*127);
        buffer_dispo[indice].b=(float)(127.0-buffer_dispo[indice].pan)*buffer_dispo[indice].vol/(127*127);
#endif
    
        buffer_dispo[indice].is_playing=TRUE;

#ifdef SUPERVISATER
                                super_info.vol=par->vol;
                                super_info.freq=get_inc_for_voice(num_sample,par->freq);
                                SendMessage(hwndSupervisater,MSG_REFRESH_SUPERVISATER,indice,(LPARAM)&super_info);
#endif

                                if (fct!=NULL)
                                {//il y a un Callback
                                                snd_dump("wait séma Callback dans PlaySnd-",0);

                                                buffer_dispo[indice].waiting_callback=TRUE;
                                                buffer_dispo[indice].fct_callback=fct;
                                }
                                else
                                {//pas de Callback; peut-être looping ?
                                if (sounddescriptor[num_sample].looping)
                                                {//loopant
                                                                                                                buffer_dispo[indice].is_looping=TRUE;
                                                                snd_dump("wait séma Looping dans PlaySnd-",0);
                                                }
                                }//fct!=NULL

                                snd_dump("->%X\n",indice);
                                buffer_dispo[indice].sample=num_sample;

                                return (indice);

                }//sounddescriptor[num_sample].dispo

                goto echec;

echec:
#endif  //#ifdef HARDSND
                return ECHEC_PLAYSND;
}
*/

/*
#ifdef SYNCHRO_CALLBACK
void CALLBACK CallbackSynchroSnd(UINT IDEvent,UINT msg,DWORD par,DWORD dw1,DWORD dw2)
{
    MMRESULT res;
    char texte[80];
    WAVEHDR *wave;

    if (dw1!=NULL)
    {
        wave=(WAVEHDR*)dw1;
        
        genere_buffer((void*)(wave->lpData),taille_buffer);

        if (driver_SND_OK)
        if ((res=waveOutWrite(WaveOut,wave,sizeof(WAVEHDR)))!=MMSYSERR_NOERROR)
        {
            sprintf(texte,"erreur %d sur waveOutWrite",res);
            snd_erreur(SND_ERREUR_INIT_DS,texte,0);
            driver_SND_OK=FALSE;
        }
    }
}
#endif //SYNCHRO_CALLBACK
*/

#ifdef REVERB
void InitReverb(void)
{
	CheckConst();
	
	DataBufferReverb=(void*)SND_fn_pvMallocSnd(2*taille_buffer+8);
        memset(DataBufferReverb,0,2*taille_buffer);
        DataBufferReverbMax=(void*)((int)DataBufferReverb+2*taille_buffer);
                ptrReverb_asm=(DWORD)DataBufferReverb;
}

void DesInitReverb(void)
{
    SND_fn_vFreeSnd(DataBufferReverb);
}
#endif //REVERB 

typedef struct
{
	SND_td_pfn_vSoundCallback fct;
	DWORD param;
} callback_param;

//thread lancée à chaque occurence de callback
//int WINAPI start_callback_thread(DWORD *param)
#if defined(__WATCOMC__) && (__WATCOMC__<1100)
void start_callback_thread(callback_param *callback_par)
#else
void __cdecl start_callback_thread(callback_param *callback_par)
#endif
{
	(callback_par->fct)(callback_par->param);

	GlobalFree(callback_par);

	//return 0;
}

//fct appelée par genere en cas de Callback
//*buffer_dispo dans esi
void __stdcall start_callback(BUFFER_DISPO *buffer)
{
//	BUFFER_DISPO *buffer;
//	DWORD id_thread;
	callback_param *callback_par;

	callback_par=GlobalAlloc(GMEM_FIXED,sizeof(callback_param));
	callback_par->fct=buffer->fct_callback;
	callback_par->param=buffer->param_callback;

	//CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)start_callback_thread,param,0,&id_thread);
#if defined(__WATCOMC__) && (__WATCOMC__<1100)
        _beginthread(start_callback_thread,NULL,0,(void*)callback_par);
#else
        _beginthread(start_callback_thread,0,(void*)callback_par);
#endif
}

/*
void start_callback()
{
	BUFFER_DISPO *buffer;
	DWORD *param;
	DWORD id_thread;

#ifdef __WATCOMC__
#pragma aux pushad
#pragma aux mov dword ptr [buffer],esi"
#else
	_asm pushad
	_asm mov buffer,esi
#endif

	param=GlobalAlloc(GMEM_FIXED,sizeof(DWORD)*2);
	param[0]=(DWORD)buffer->fct_callback;
	param[1]=buffer->param_callback;

	CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)start_callback_thread,param,0,&id_thread);

#ifdef __WATCOMC__
#pragma aux popad
#else
	_asm popad
#endif
}
*/

#else //DISABLE_WAVE
long DataBufferReverb,DataBuffer,DataBufferReverbMax;
long NBVJ,NBVM;
long DeltaReverb,buffer_dispo_max,buffer_dispo_min,taille_buffer;
void __stdcall start_callback(long toto)
{
}

#endif //DISABLE_WAVE

#define SND_fn_bTestSnd_Processor() SND_fn_bTestSnd_Pentium()
#define C_PROCESSOR_WANTED "Pentium or compatible"

//-----------------------------------------------------
//	Retourne le label désignant la target associée à la DLL
//	Entrée:name=cible de 256 char
//-----------------------------------------------------
void SND_fn_vGetTargetLabelSample(char* name,int nb_char)
{
	strncpy(name,"pw",nb_char);
}

void SND_fn_vSetupTargetSample(void)
{
	//Erm_fn_iMessageBox(HWND_DESKTOP,"WinMM for Pentium","Sound Module",MB_OK);
	//rien
}

SndBool SND_fn_bCanSetupTargetSample(void)
{
	return TRUE;
}


#include "sndwave.cxx"

