sound, music, mixer

This commit is contained in:
Ondřej Novák 2025-02-02 14:29:06 +01:00
parent 42087c926c
commit f8a1501289
42 changed files with 1345 additions and 157 deletions

View file

@ -13,7 +13,8 @@ SET(files basicobj.c
pcx.c
strlite.c
wav_mem.c
strlists.c
strlists.c
music.cpp
swaper.c )
add_library(skeldal_libs ${files})

View file

@ -69,7 +69,7 @@
#include <libs/bgraph.h>
#include <libs/memman.h>
#include <libs/zvuk.h>
#include <platform/sound.h>
//#include <vesa.h>
//#include <i86.h>

View file

@ -5,7 +5,7 @@
#include "memman.h"
#include "mem.h"
#include "mgifmem.h"
#include <libs/zvuk.h>
#include <platform/sound.h>
static MGIF_HEADER_T *mgif_header;

161
libs/music.cpp Normal file
View file

@ -0,0 +1,161 @@
#include "music.h"
#include <platform/platform.h>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string_view>
#include <vector>
#include <utility>
class MUSStreamParser: public IMusicStream {
public:
MUSStreamParser(const char *name) {
data = map_file_to_memory(file_icase_find(name), &sz);
if (data) {
_loaded = true;
iter = reinterpret_cast<const uint8_t *>(data);
chans = read_short();
freq = read_int();
iter += 4;
blocks = read_int();
iter += 8;
std::memcpy(btable,iter,sizeof(btable));
iter += sizeof(btable);
btable[0] = -31767;
}
}
~MUSStreamParser() {
if (data) unmap_file(data, sz);
}
MUSStreamParser(const MUSStreamParser &) = delete;
MUSStreamParser& operator=(const MUSStreamParser &) = delete;
bool is_loaded() const {return _loaded;}
virtual TMUSIC_STREAM_INFO get_info() const override {
TMUSIC_STREAM_INFO r;
r.format = 2;
r.channels = chans;
r.freq = freq;
return r;
}
virtual std::string_view read() override {
if (unprocessed_buffer.empty()) {
if (!process_next()) return {};
}
return std::exchange(unprocessed_buffer, {});
}
virtual void put_back(std::string_view data) override {
unprocessed_buffer = data;
}
protected:
bool _loaded = false;
void *data;
std::size_t sz;
std::int16_t chans;
std::int32_t freq;
std::int32_t blocks;
short btable[256];
const uint8_t *iter;
std::vector<int16_t> outbuff;
std::string_view unprocessed_buffer;
int32_t read_int() {
int32_t r = iter[0] | (iter[1] << 8) | (iter[2]<<16) | (iter[3] << 24);
iter+=4;
return r;
}
int16_t read_short() {
int16_t r = iter[0] | (iter[1] << 8);
iter+=2;
return r;
}
bool process_next() {
if (blocks == 0) {
return false;
}
--blocks;
std::int32_t p = read_int();
read_int();
outbuff.clear();
short accum[2]={0,0};
int c = 0;
for (int i = 0; i < p; ++i) {
uint8_t p = *iter++;
short val=accum[c]+btable[p];
accum[c]=val;
/*
if (p==0) //pridano jako provizorni reseni pro korekci chyby komprimacniho programu
{
val-=31767;
}
*/
c = (c + 1) % chans;
outbuff.push_back(val);
}
unprocessed_buffer = {reinterpret_cast<const char *>(outbuff.data()), outbuff.size()*2};
return true;
}
};
void music_close(TMUSIC_STREAM *stream) {
if (stream) {
IMusicStream *s = static_cast<IMusicStream *>(stream);
delete s;
}
}
TMUSIC_STREAM *music_open(const char *filename) {
MUSStreamParser *player = new MUSStreamParser(filename);
if (player->is_loaded()) return player;
delete player;
return NULL;
}
TMUSIC_STREAM_CHUNK music_read(TMUSIC_STREAM *stream) {
TMUSIC_STREAM_CHUNK r = {NULL,0};
if (stream) {
IMusicStream *s = static_cast<IMusicStream *>(stream);
auto data = s->read();
r.ptr = data.data();
r.sz = data.size();
}
return r;
}
char music_is_eof(const TMUSIC_STREAM_CHUNK *chunk) {
return chunk->sz == 0;
}
void music_put_back_chunk(TMUSIC_STREAM *stream, const TMUSIC_STREAM_CHUNK *chunk){
if (stream) {
IMusicStream *s = static_cast<IMusicStream *>(stream);
s->put_back({reinterpret_cast<const char *>(chunk->ptr), chunk->sz});
}
}
TMUSIC_STREAM_INFO music_get_info(const TMUSIC_STREAM *stream) {
if (stream) {
const IMusicStream *s = static_cast<const IMusicStream *>(stream);
return s->get_info();
} else {
TMUSIC_STREAM_INFO r = {};
return r;
}
}

51
libs/music.h Normal file
View file

@ -0,0 +1,51 @@
#pragma once
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct music_stream_t {} TMUSIC_STREAM;
typedef struct music_stream_info_t {
int freq;
int channels;
int format; //1 - uint8_t. 2 - int16_t
} TMUSIC_STREAM_INFO;
typedef struct music_stream_chunk_t {
const void *ptr;
size_t sz;
} TMUSIC_STREAM_CHUNK;
///open music stream
TMUSIC_STREAM *music_open(const char *filename);
///retrieve information
TMUSIC_STREAM_INFO music_get_info(const TMUSIC_STREAM *stream);
TMUSIC_STREAM_CHUNK music_read(TMUSIC_STREAM *stream);
char music_is_eof(const TMUSIC_STREAM_CHUNK *chunk);
void music_put_back_chunk(TMUSIC_STREAM *stream, const TMUSIC_STREAM_CHUNK *chunk);
///close music stream
void music_close(TMUSIC_STREAM *stream);
#ifdef __cplusplus
}
#include <string_view>
class IMusicStream: public TMUSIC_STREAM {
public:
virtual ~IMusicStream() = default;
virtual TMUSIC_STREAM_INFO get_info() const = 0;
virtual std::string_view read() = 0;
virtual void put_back(std::string_view data) = 0;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,74 +0,0 @@
#ifndef __ZVUK_H___
#define __ZVUK_H___
#ifdef __cplusplus
extern "C" {
#endif
#define BACK_BUFF_SIZE 0x40000
#define DEV_NOSOUND 0
#define DEV_SB10 1
#define DEV_SB20 2
#define DEV_SBPRO 3
#define DEV_SB16 4
#define DEV_WSS 5
#define DEV_ULTRA 6
#define DEV_DAC 7
#define DEV_PCSPEAKER 8
#define DEV_DIRECTSOUND 9 //only valid device for this module
extern int bvolume;
int sound_detect(int *dev,int *port,int *dma, int *irq);
void set_mixing_device(int mix_dev,int mix_freq,...);
char start_mixing(void);
void stop_mixing(void);
void play_sample(int channel,const void *sample,int32_t size,int32_t lstart,int32_t sfreq,int type);
void set_channel_volume(int channel,int left,int right);
void set_end_of_song_callback(const char * (*cb)(void *), void *ctx);
void fade_music(void);
int mix_back_sound(int synchro);
int open_backsound(char *filename);
void change_music(const char *filename);
int get_timer_value(void);
const char *device_name(int device);
void force_music_volume(int volume);
void set_backsnd_freq(int freq);
char get_channel_state(int channel);
void get_channel_volume(int channel,int *left,int *right);
void mute_channel(int channel);
void chan_break_loop(int channel);
void chan_break_ext(int channel,const void *org_sample,int32_t size_sample); //zrusi loop s moznosti dohrat zvuk
char set_snd_effect(int funct,int data);
char check_snd_effect(int funct);
int get_snd_effect(int funct);
void *PrepareVideoSound(int mixfreq, int buffsize);
char LoadNextVideoFrame(void *buffer, const char *data, int size, const short *xlat, short *accnums, int32_t *writepos);
void DoneVideoSound(void *buffer);
#define SND_MAXFUNCT 11
#define SND_PING 0 //Ping function
#define SND_GVOLUME 1 //SetGlobalVolume
#define SND_BASS 2 //SetBass
#define SND_TREBL 3 //SetTrebles
#define SND_SWAP 4 //SetSwapChannels
#define SND_LSWAP 5 //SetLinearSwapping
#define SND_SURROUND 6 //Surrourd
#define SND_OUTFILTER 7//Out Filter
#define SND_GFX 8 //setgfxvolume
#define SND_MUSIC 9 //setmusicvolume
#define SND_XBASS 10 //setxbassy
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,842 +0,0 @@
#define INITGUID
#include <platform/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 <libs/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();
}
}

File diff suppressed because it is too large Load diff