gates_of_skeldal/libs/zvuk_dx.cpp
2025-01-26 21:36:03 +01:00

842 lines
21 KiB
C++

#define INITGUID
#include <platform.h>
#include <malloc.h>
#include <debug.h>
#include <stdio.h>
#define DWORD_PTR DWORD *
#include <dsound.h>
#include "types.h"
#include "zvuk.h"
#include <math.h>
extern "C" {
#include <memman.h>
}
#define MAXCHANNELS 32
#define TIMEIDLESTOPCHANNEL 250
#define DEFAULTBUFFERSIZE (256*1024)
#define FADELENGTH 3000
#define MUS_ERRORWAIT 5000
#include "Music.h"
static int cur_device=0;
static int cur_mixfreq=0;
static bool swap_chans=false;
class CheckRes
{
public:
HRESULT operator=(HRESULT other)
{
if (other==0) return 0;
char buff[256];
sprintf(buff,"DirectSound error HRESULT %08X, code %d",other,other & 0xFFFF);
int id=MessageBox(NULL,buff,NULL,MB_SYSTEMMODAL|MB_ABORTRETRYIGNORE);
if (id==IDRETRY)
{
__asm int 3;
return other;
}
if (id==IDIGNORE) return other;
exit(-1);
}
};
static CheckRes hres;
static HWND hWndDS8=NULL;
static IDirectSound8 *ds8=NULL;
static IDirectSoundBuffer *ds_primary;
static WAVEFORMATEX waveformat;
static int gfx_volume=255;
static int music_volume=127;
static int glob_volume=255;
static int linvoltable[256];
static MusicPlayer GMusicPlayer;
static MusDecoder GMusDecoder;
static WinAmpDecoder GWinAmpPlayer;
static IDecoder *GCurrentDecoder=&GMusDecoder;
class SoundChannelInfo
{
public:
CRITICAL_SECTION sect;
char *play_pos, *start_loop, *end_loop;
IDirectSoundBuffer8 *buffer;
uint32_t chantype;
uint32_t idsPlayPos;
uint32_t idsWritePos;
uint32_t idsBuffSize;
int32_t volume; //volume for DS
int32_t pan; //pan for DS
int volleft; //left volume for skeldal
int volright; //right volume for skeldal
uint32_t preload;
uint32_t stopTime; //time, when buffer reached end. For calculating idle time
uint32_t startTime; //time, when buffer started. For calculating idle time, use 0 to sticky buffer
SoundChannelInfo()
{
buffer=NULL;
play_pos=start_loop=end_loop=NULL;
InitializeCriticalSection(&sect);
pan=DSBPAN_CENTER;
volume=DSBVOLUME_MAX;
}
~SoundChannelInfo() {if (buffer) buffer->Release();DeleteCriticalSection(&sect);}
uint32_t CalculateLockSize();
void ChannelMaintaince();
bool IsPlaying() {return play_pos!=NULL;}
// bool IsFree(char type) {return play_pos==NULL || (type==chantype && play_pos==end_loop);}
void Reset();
void InitChannel(char type, char *ppos, char *bloop,char *eloop, int freq);
void Lock() {EnterCriticalSection(&sect);}
void Unlock() {LeaveCriticalSection(&sect);}
bool TryLock() {return TryEnterCriticalSection(&sect)!=FALSE;}
void SetVolume(int32_t vol)
{
Lock();
if (volume!=vol) if (buffer && play_pos ) hres=buffer->SetVolume(vol);
volume=vol;
Unlock();
}
void SetPan(int32_t p)
{
Lock();
if (pan!=p) if (buffer && play_pos ) hres=buffer->SetPan(p);
pan=p;
Unlock();
}
void Mute()
{
Lock();
Stop();
Unlock();
}
void Stop()
{
if (buffer)
buffer->Stop();
play_pos=NULL;
}
void BreakLoop() {start_loop=end_loop;}
void BreakLoopEx(char *end_sample) {start_loop=end_loop=end_sample;}
};
static bool shutMaintaince=false;
static SoundChannelInfo channels[MAXCHANNELS];
static HANDLE maintainceThread;
ULONG __stdcall MaintainceThread(void *);
static void DSStart(int mixfreq)
{
DSBUFFERDESC desc;
for (int i=1;i<256;i++)
{
double rang=pow(i/255.0,15);
linvoltable[i]=100*log(rang);
}
linvoltable[0]=-10000;
hres=DirectSoundCreate8(&DSDEVID_DefaultPlayback,&ds8,NULL);
if (hWndDS8) hres=ds8->SetCooperativeLevel(hWndDS8,DSSCL_PRIORITY);
memset(&desc,0,sizeof(desc));
desc.dwSize=sizeof(desc);
desc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME;
hres=ds8->CreateSoundBuffer(&desc,&ds_primary,NULL);
waveformat.cbSize=sizeof(waveformat);
waveformat.nBlockAlign=4;
waveformat.nChannels=2;
waveformat.nSamplesPerSec=mixfreq;
waveformat.nAvgBytesPerSec=mixfreq*4;
waveformat.wBitsPerSample=16;
waveformat.wFormatTag=WAVE_FORMAT_PCM;
hres=ds_primary->SetFormat(&waveformat);
DWORD id;
shutMaintaince=false;
maintainceThread=CreateThread(NULL,0,MaintainceThread,NULL,0,&id);
SetThreadPriority(maintainceThread,THREAD_PRIORITY_HIGHEST);
GMusicPlayer.InitBuffer(ds8,linvoltable);
GMusicPlayer.Play();
}
void init_winamp_plugins(const char *path)
{
GWinAmpPlayer.LoadPlugins(path);
}
static void DSStop()
{
GCurrentDecoder->Stop();
GMusDecoder.Stop();
GMusicPlayer.Done();
GWinAmpPlayer.ClearList();
shutMaintaince=true;
WaitForSingleObject(maintainceThread,INFINITE);
CloseHandle(maintainceThread);
for (int i=0;i<MAXCHANNELS;i++)
if (channels[i].buffer)
{channels[i].Stop(); channels[i].buffer->Release();channels[i].buffer=NULL;}
if (ds_primary) ds_primary->Release();
ds_primary=NULL;
if (ds8) ds8->Release();
ds8=NULL;
}
uint32_t SoundChannelInfo::CalculateLockSize()
{
if (buffer==NULL) return 0;
uint32_t playpos;
buffer->GetCurrentPosition(NULL,&playpos);
int32_t diff=(signed)playpos-(signed)idsPlayPos;
if (diff<0) diff+=idsBuffSize;
uint32_t wendpos=playpos+preload;
if (wendpos>=idsBuffSize) wendpos-=idsBuffSize;
if (wendpos<idsWritePos && wendpos>playpos) return 0;
if (wendpos<idsWritePos) wendpos+=idsBuffSize;
uint32_t sz=(wendpos-idsWritePos+3) & ~3;
if (sz>idsBuffSize/2) sz=idsBuffSize/2;
idsPlayPos=playpos;
return sz;
}
void SoundChannelInfo::ChannelMaintaince()
{
Lock();
if (play_pos!=NULL)
{
if (play_pos!=end_loop) stopTime=GetTickCount();
uint32_t lockSize=CalculateLockSize();
if (lockSize)
{
// printf("%8d\r",lockSize);
void *audioptrs[2];
uint32_t sizes[2];
hres=buffer->Lock(idsWritePos,lockSize,audioptrs,sizes,audioptrs+1,sizes+1,0);
for (int i=0;i<2 && audioptrs[i];i++)
{
char *wrt=(char *)audioptrs[i];
for (uint32_t j=0;j<sizes[i];j++) if (play_pos!=end_loop)
{
*wrt++=*play_pos++;
if (play_pos==end_loop) play_pos=start_loop;
}
else
{
if (chantype & 0x1) *wrt++=0x80; else *wrt++=0;
}
}
hres=buffer->Unlock(audioptrs[0],sizes[0],audioptrs[1],sizes[1]);
idsWritePos+=lockSize;
if (idsWritePos>=idsBuffSize) idsWritePos-=idsBuffSize;
}
if (play_pos==end_loop && GetTickCount()-stopTime>TIMEIDLESTOPCHANNEL)
{
Stop();
}
}
Unlock();
}
static void MixMaintaince()
{
for (int i=0;i<MAXCHANNELS;i++) channels[i].ChannelMaintaince();
}
static ULONG __stdcall MaintainceThread(void *)
{
while (!shutMaintaince) {MixMaintaince();Sleep(50);}
return 0;
}
void SoundChannelInfo::Reset()
{
Lock();
if (buffer) buffer->Release();
buffer=NULL;
Unlock();
}
void SoundChannelInfo::InitChannel(char type, char *ppos, char *bloop,char *eloop, int freq)
{
Lock();
uint32_t newchantype=type+freq*4;
if (chantype!=newchantype || buffer==NULL)
{
Reset();
DSBUFFERDESC desc;
WAVEFORMATEX wfex;
wfex.cbSize=sizeof(wfex);
wfex.wFormatTag=WAVE_FORMAT_PCM;
wfex.wBitsPerSample=type==1?8:16;
wfex.nSamplesPerSec=freq;
wfex.nChannels=1;
wfex.nBlockAlign=type==1?1:2;
wfex.nAvgBytesPerSec=wfex.nBlockAlign*wfex.nSamplesPerSec;
memset(&desc,0,sizeof(desc));
desc.dwSize=sizeof(desc);
desc.dwFlags=DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME|DSBCAPS_GETCURRENTPOSITION2;
desc.dwBufferBytes=DEFAULTBUFFERSIZE;
desc.lpwfxFormat=&wfex;
preload=wfex.nAvgBytesPerSec/5;
IDirectSoundBuffer *bufold;
hres=ds8->CreateSoundBuffer(&desc,&bufold,NULL);
hres=bufold->QueryInterface(IID_IDirectSoundBuffer8,(void **)&buffer);
bufold->Release();
idsPlayPos=DEFAULTBUFFERSIZE-cur_mixfreq;
idsWritePos=0;
idsBuffSize=DEFAULTBUFFERSIZE;
play_pos=ppos;
start_loop=bloop;
end_loop=eloop;
chantype=newchantype;
hres=buffer->SetVolume(volume);
hres=buffer->SetPan(pan);
ChannelMaintaince();
hres=buffer->Play(0,0,DSBPLAY_LOOPING);
stopTime=startTime=GetTickCount();
}
else
{
buffer->Stop();
idsBuffSize=DEFAULTBUFFERSIZE;
buffer->SetCurrentPosition(0);
buffer->GetCurrentPosition(&idsPlayPos,&idsWritePos);
hres=buffer->SetVolume(volume);
hres=buffer->SetPan(pan);
play_pos=ppos;
start_loop=bloop;
end_loop=eloop;
ChannelMaintaince();
buffer->Play(0,0,DSBPLAY_LOOPING);
stopTime=startTime=GetTickCount();
}
Unlock();
}
/*
static int FindFreeChannel(char type)
{
int older=0;
DWORD m_age=0;
DWORD timval=GetTickCount();
for (int i=0;i<MAXCHANNELS;i++) if (!channels[i].IsFree(char type)) return i;
{
DWORD age==timval-channels[i].startTime;
if (age>m_age) {older=i;m_age=age;}
}
return older;
}
*/
extern "C"
{
int bvolume; //background volume
void (*konec_skladby)(char **jmeno)=NULL; //pointer to function to notify that end of song has been reached
void DSReportWindowCreation(HWND hWindow)
{
hWndDS8=hWindow;
if (ds8!=NULL) hres=ds8->SetCooperativeLevel(hWndDS8,DSSCL_PRIORITY);
}
int sound_detect(int *dev,int *port,int *dma, int *irq)
{
*dev=DEV_DIRECTSOUND;
*port=0;
*dma=0;
*irq=0;
return 0;
}
void set_mixing_device(int mix_dev,int mix_freq,...)
{
cur_device=mix_dev;
cur_mixfreq=mix_freq;
}
char start_mixing()
{
if (cur_device!=DEV_DIRECTSOUND)
{
MessageBox(hWndDS8,"Invalid sound device! Check SKELDAL.INI. Only device 9 (DirectSound) can be used.",NULL,MB_SYSTEMMODAL);
exit(1);
}
if (cur_mixfreq==0) return FALSE;
DSStart(cur_mixfreq);
return TRUE;
}
void stop_mixing()
{
DSStop();
}
void play_sample(int channel,void *sample,int32_t size,int32_t lstart,int32_t sfreq,int type)
{
char *start=(char *)sample;
channels[channel].InitChannel(type,start,start+lstart,start+size,sfreq);
}
void set_channel_volume(int channel,int left,int right)
{
if (left>32767) left=32767;
if (left<0) left=0;
if (right>32767) right=32767;
if (right<0) right=0;
int volleft=linvoltable[(left>>7)*gfx_volume/255];
int volright=linvoltable[(right>>7)*gfx_volume/255];
int volsum=__max(volleft,volright);
channels[channel].SetVolume(volsum);
channels[channel].SetPan(swap_chans?(volright-volleft):(volleft-volright));
channels[channel].volleft=left;
channels[channel].volright=right;
}
char get_channel_state(int channel)
{
return channels[channel].IsPlaying()==true;
}
void get_channel_volume(int channel,int *left,int *right)
{
if (left) *left=channels[channel].volleft;
if (right) *right=channels[channel].volright;
}
void mute_channel(int channel)
{
channels[channel].Mute();
}
void chan_break_loop(int channel)
{
channels[channel].BreakLoop();
}
void chan_break_ext(int channel,void *org_sample,int32_t size_sample) //zrusi loop s moznosti dohrat zvu
{
char *end_sample=(char *)org_sample+size_sample;
channels[channel].BreakLoopEx(end_sample);
}
char set_snd_effect(int funct,int data)
{
switch (funct)
{
case SND_PING: return 1;
case SND_SWAP: swap_chans=(data & 1)!=0;return 1;
case SND_GFX: gfx_volume=data;return 1;
case SND_MUSIC: GCurrentDecoder->SetVolume(music_volume=data,get_snd_effect(SND_GVOLUME));return 1;
case SND_GVOLUME: hres=ds_primary->SetVolume(linvoltable[glob_volume=data]);return 1;
default: return 0;
}
}
int get_snd_effect(int funct)
{
switch (funct)
{
case SND_PING: return 1;
case SND_SWAP: return swap_chans;
case SND_GFX: return gfx_volume;
case SND_MUSIC: return music_volume;
case SND_GVOLUME: return glob_volume;
default: return 0;
}
}
char check_snd_effect(int funct)
{
switch (funct)
{
case SND_PING:
case SND_SWAP:
case SND_MUSIC:
case SND_GVOLUME:
case SND_GFX: return 1;
default: return 0;
}
}
static DWORD Mus_buffSize;
/*
static HANDLE music_file=NULL;
static HANDLE next_music_file=NULL;
static bool fading=false;
static DWORD fadetime;
static DWORD Mus_lastWritePos;
static DWORD Mus_nextBlockSize;
static DWORD Mus_nextBlockRead;
static DWORD Mus_errorWait=0;
static DWORD Mus_silentPlay=0;
#pragma pack (1)
struct MusFile
{
short channels;
int32_t freq;
int32_t ssize;
int32_t blocks;
int32_t reserved1;
int32_t reserved2;
short ampltable[256];
};
static MusFile curMus;
#pragma pack()
static char OpenMus(HANDLE music_file)
{
DWORD bytesread;
SetFilePointer(music_file,0,NULL,FILE_BEGIN);
if (ReadFile(music_file,&curMus,sizeof(curMus),&bytesread,NULL)==TRUE && bytesread==sizeof(curMus))
{
if (ReadFile(music_file,&Mus_nextBlockRead,sizeof(Mus_nextBlockRead),&bytesread,NULL)==FALSE) return 0;
if (ReadFile(music_file,&Mus_nextBlockSize,sizeof(Mus_nextBlockSize),&bytesread,NULL)==FALSE) return 0;
if (ds_music!=NULL) ds_music->Release();
WAVEFORMATEX wfex;
wfex.cbSize=sizeof(wfex);
wfex.wBitsPerSample=16;
wfex.nBlockAlign=2*curMus.channels;
wfex.nSamplesPerSec=curMus.freq;
wfex.nAvgBytesPerSec=curMus.freq*wfex.nBlockAlign;
wfex.wFormatTag=WAVE_FORMAT_PCM;
wfex.nChannels=curMus.channels;
DSBUFFERDESC desc;
desc.dwSize=sizeof(desc);
desc.dwBufferBytes=Mus_buffSize=wfex.nAvgBytesPerSec*4;
desc.dwReserved=0;
desc.dwFlags=DSBCAPS_CTRLVOLUME ;
desc.lpwfxFormat=&wfex;
IDirectSoundBuffer *dsbf;
hres=ds8->CreateSoundBuffer(&desc,&dsbf,NULL);
hres=dsbf->QueryInterface(IID_IDirectSoundBuffer8,(void **)&ds_music);
dsbf->Release();
void *ptr;
DWORD size;
ds_music->Lock(0,0,&ptr,&size,NULL,NULL,DSBLOCK_ENTIREBUFFER);
memset(ptr,0,size);
ds_music->Unlock(ptr,size,NULL,NULL);
ds_music->SetVolume(linvoltable[music_volume]);
ds_music->Play(0,0,DSBPLAY_LOOPING);
fadetime=0;
Mus_lastWritePos=wfex.nAvgBytesPerSec;
Mus_silentPlay=0;
return 1;
}
return 0;
}
static void PrepareMusFile(const char *filename)
{
CloseHandle(next_music_file);
next_music_file=CreateFile(filename,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (next_music_file==INVALID_HANDLE_VALUE)
next_music_file=NULL;
}
static char music_decompres_block()
{
DWORD bytesread;
char *data=(char *)alloca(Mus_nextBlockRead);
short accum[2]={0,0};
char curchan=0;
DWORD lockSizes[2];
void *lockPtrs[2];
if (ReadFile(music_file,data,Mus_nextBlockRead,&bytesread,NULL)==FALSE) return 0;
ds_music->Lock(Mus_lastWritePos,Mus_nextBlockSize,lockPtrs,lockSizes,lockPtrs+1,lockSizes+1,0);
for (int j=0;j<2;j++)
{
short *target=(short *)lockPtrs[j];
for (DWORD i=0;i<lockSizes[j];i+=2)
{
short val=accum[curchan]+curMus.ampltable[*data++];
accum[curchan]=val;
if (data[-1]==0) //pridano jako provizorni reseni pro korekci chyby komprimacniho programu
{
val-=31767;
}
if (fadetime)
{
int32_t ftime=FADELENGTH-(GetTickCount()-fadetime);
if (ftime<0) ftime=0;
float mul=(float)ftime*(float)ftime/(float)(FADELENGTH*FADELENGTH);
val=(short)(val*mul);
}
*target++=val;
curchan++;
if (curchan>=curMus.channels) curchan=0;
}
}
ds_music->Unlock(lockPtrs[0],lockSizes[0],lockPtrs[1],lockSizes[1]);
Mus_lastWritePos+=Mus_nextBlockSize;
if (Mus_lastWritePos>=Mus_buffSize) Mus_lastWritePos-=Mus_buffSize;
return 1;
}
static char music_silent_play()
{
DWORD lockSizes[2];
void *lockPtrs[2];
ds_music->Lock(Mus_lastWritePos,Mus_nextBlockSize,lockPtrs,lockSizes,lockPtrs+1,lockSizes+1,0);
for (int j=0;j<2;j++)
{
short *target=(short *)lockPtrs[j];
for (DWORD i=0;i<lockSizes[j];i+=2)
{
*target++=0;
}
}
ds_music->Unlock(lockPtrs[0],lockSizes[0],lockPtrs[1],lockSizes[1]);
Mus_lastWritePos+=Mus_nextBlockSize;
if (Mus_lastWritePos>=Mus_buffSize) Mus_lastWritePos-=Mus_buffSize;
return 1;
}
void fade_music()
{
if (fadetime==0) fadetime=music_file?GetTickCount():0;
}
static int mix_back_sound_worker()
{
DWORD bytesread;
if (music_file==NULL) return -2;
if (ds_music==NULL)
if (OpenMus(music_file)==0) return -2;
DWORD play;
ds_music->GetCurrentPosition(&play,NULL);
while (true)
{
if (Mus_lastWritePos<=play)
{
if (Mus_lastWritePos+Mus_nextBlockSize>=play) return 0;
}
else
{
if (Mus_lastWritePos+Mus_nextBlockSize>play+Mus_buffSize) return 0;
}
if (Mus_silentPlay)
{
if (Mus_silentPlay>GetTickCount())
{
music_silent_play();
return 0;
}
else
return -2;
}
if (music_decompres_block()==0) return -2;
curMus.blocks--;
if (curMus.blocks<0)
{
Mus_silentPlay=GetTickCount()+4000;
return 0;
}
if (ReadFile(music_file,&Mus_nextBlockRead,sizeof(Mus_nextBlockRead),&bytesread,NULL)==FALSE) return -2;
if (ReadFile(music_file,&Mus_nextBlockSize,sizeof(Mus_nextBlockSize),&bytesread,NULL)==FALSE) return -2;
if (fadetime && fadetime+FADELENGTH<GetTickCount())
{
Mus_silentPlay=GetTickCount()+4000;
return 0;
}
}
Mus_errorWait=0;
return 0;
}
*/
int mix_back_sound(int synchro)
{
if (GCurrentDecoder->IsPlaying()) return 0;
char *next_music;
konec_skladby(&next_music);
change_music(next_music);
return 0;
}
void change_music(const char *mus_filename)
{
if (GCurrentDecoder->NotUsingOutput()) GMusDecoder.Stop();
GCurrentDecoder->Stop();
if (mus_filename==0)
{
mus_filename="?";
GCurrentDecoder=&GMusDecoder;
}
else
{
const char *c=strrchr(mus_filename,'.');
if (c!=0 && stricmp(c,".mus")==0)
GCurrentDecoder=&GMusDecoder;
else
GCurrentDecoder=&GWinAmpPlayer;
}
GCurrentDecoder->AttachOutput(&GMusicPlayer);
if (GCurrentDecoder->Play(mus_filename)==false) change_music(0);
GCurrentDecoder->SetVolume(music_volume,get_snd_effect(SND_GVOLUME));
if (GCurrentDecoder->NotUsingOutput())
GMusDecoder.Play("?");
}
int get_timer_value()
{
return GetTickCount()/TIMERSPEED
}
char *device_name(int device)
{
if (device!=DEV_DIRECTSOUND) return "Unknown device!";
else return "DirectSound 8";
}
void force_music_volume(int volume)
{
}
void set_backsnd_freq(int bfreq)
{
}
void *PrepareVideoSound(int mixfreq, int buffsize)
{
WAVEFORMATEX wfex;
wfex.cbSize=sizeof(wfex);
wfex.wBitsPerSample=16;
wfex.nBlockAlign=4;
wfex.nSamplesPerSec=mixfreq;
wfex.nAvgBytesPerSec=mixfreq*wfex.nBlockAlign;
wfex.wFormatTag=WAVE_FORMAT_PCM;
wfex.nChannels=2;
DSBUFFERDESC desc;
desc.dwSize=sizeof(desc);
desc.dwBufferBytes=Mus_buffSize=buffsize;
desc.dwReserved=0;
desc.dwFlags=DSBCAPS_CTRLVOLUME ;
desc.lpwfxFormat=&wfex;
IDirectSoundBuffer *dsbf;
IDirectSoundBuffer8 *ds_music;
hres=ds8->CreateSoundBuffer(&desc,&dsbf,NULL);
hres=dsbf->QueryInterface(IID_IDirectSoundBuffer8,(void **)&ds_music);
dsbf->Release();
void *ptr;
DWORD size;
ds_music->Lock(0,0,&ptr,&size,NULL,NULL,DSBLOCK_ENTIREBUFFER);
memset(ptr,0,size);
ds_music->Unlock(ptr,size,NULL,NULL);
ds_music->SetVolume(0);
ds_music->Play(0,0,DSBPLAY_LOOPING);
return (void *)ds_music;
}
char LoadNextVideoFrame(void *buffer, char *data, int size, short *xlat,short *accnums, int32_t *writepos)
{
IDirectSoundBuffer8 *ds_music=(IDirectSoundBuffer8 *)buffer;
DSBCAPS caps;
caps.dwSize=sizeof(caps);
ds_music->GetCaps(&caps);
DWORD play;
ds_music->GetCurrentPosition(&play,NULL);
int32_t remain=play-*writepos;
if (remain<0) remain+=caps.dwBufferBytes;
if (remain<size*2) return 0;
char curchan=0;
DWORD lockSizes[2];
void *lockPtrs[2];
ds_music->Lock(*writepos,size*2,lockPtrs,lockSizes,lockPtrs+1,lockSizes+1,0);
for (int j=0;j<2;j++)
{
short *target=(short *)lockPtrs[j];
for (DWORD i=0;i<lockSizes[j];i+=2)
{
int val=accnums[curchan]+xlat[*data++];
if (val>32767)
{accnums[curchan]-=val-32768;val=32767;}
if (val<-32767)
{accnums[curchan]-=val+32768;val=-32767;}
accnums[curchan]=val;
/* if (data[-1]==0) //pridano jako provizorni reseni pro korekci chyby komprimacniho programu
{
val-=31767;
}*/
*target++=val;
curchan++;
if (curchan>=2) curchan=0;
}
}
ds_music->Unlock(lockPtrs[0],lockSizes[0],lockPtrs[1],lockSizes[1]);
writepos[0]+=size*2;
if (writepos[0]>caps.dwBufferBytes) writepos[0]-=caps.dwBufferBytes;
return 1;
}
void DoneVideoSound(void *buffer)
{
IDirectSoundBuffer8 *ds_music=(IDirectSoundBuffer8 *)buffer;
ds_music->Stop();
ds_music->Release();
}
}