mirror of
https://github.com/ondra-novak/gates_of_skeldal.git
synced 2025-07-14 10:21:51 -04:00
sound, music, mixer
This commit is contained in:
parent
42087c926c
commit
f8a1501289
42 changed files with 1345 additions and 157 deletions
|
@ -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})
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
161
libs/music.cpp
Normal 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
51
libs/music.h
Normal 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
|
1425
libs/zvuk.c
1425
libs/zvuk.c
File diff suppressed because it is too large
Load diff
74
libs/zvuk.h
74
libs/zvuk.h
|
@ -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
|
||||
|
842
libs/zvuk_dx.cpp
842
libs/zvuk_dx.cpp
|
@ -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(§);
|
||||
pan=DSBPAN_CENTER;
|
||||
volume=DSBVOLUME_MAX;
|
||||
}
|
||||
~SoundChannelInfo() {if (buffer) buffer->Release();DeleteCriticalSection(§);}
|
||||
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(§);}
|
||||
void Unlock() {LeaveCriticalSection(§);}
|
||||
bool TryLock() {return TryEnterCriticalSection(§)!=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();
|
||||
}
|
||||
|
||||
}
|
||||
|
1247
libs/zvuka.asm
1247
libs/zvuka.asm
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue