home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 7 Games
/
07-Games.zip
/
billy164.zip
/
src
/
dart
/
dart.cc
next >
Wrap
C/C++ Source or Header
|
1997-09-21
|
15KB
|
627 lines
#define INCL_OS2MM /* required for MCI and MMIO headers */
#define INCL_DOS
#define INCL_DOSFILEMGR /* _read_key til getch */
#include <os2.h>
#include <os2me.h>
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <iostream.h>
#include <fstream.h>
#include <assert.h>
#include "inttype.h"
#include "dart.h"
#ifdef DEMO
#include "aflus.h"
#else
#define aflus cerr
#endif
#define MIX_BUFFER_EOS 0
#define STRING_LENGTH 128
#define MAX_BUFFERS 256
#include "utils.h"
#define UD(a) { for (int i=0; i<sizeof(a)/sizeof(int); i++) cerr<<" "<<((int*)&a)[i]; cerr<<endl; }
int dError=0;
char *dErrorMsg[]={"ingen lyd"};
static USHORT usDeviceID; /* Amp Mixer device id */
static ULONG bufteller; /* Current file buffer */
static ULONG antbuffere; /* Number of file buffers */
static MCI_MIX_BUFFER MixBuffers[MAX_BUFFERS]; /* Device buffers */
static MCI_MIXSETUP_PARMS MixSetupParms; /* Mixer parameters */
static MCI_BUFFER_PARMS BufferParms; /* Device buffer parms */
static ULONG rc;
static dword sidstemmtime;
static dword mmtimeperbuf;
static dword bufferlgd;
struct MixTid {int buf,ofs;};
struct intkanalT {
int vol;
Sample *samp;
int finito;
int lgd;
MixTid start;
};
#define ANTKANALER 8
struct intkanalT intkanaler[ANTKANALER];
static int mastervol = 100;
int *mixbuf32;
int mixenbuffer=0;
int operator -(const MixTid &t1, const MixTid &t2)
{return (t1.buf-t2.buf)*bufferlgd+(t1.ofs-t2.ofs);}
void mix(byte *dmabuf8, int mixlgd, int *tmpbuf32, MixTid mixfra)
{
// max for een kanal er: 6+8+8+6=28 bit
// 64 (kanalvol)*256 (mastervol)*256 (8 bit sample)*64 (samplevol)
// 28-8=20 er så det der skal skiftes med, hvis man kun har en kanal
// Vi har 8, så en bedre værdi er nok 21.
#define MIXSKIFTBIT 21
struct intkanalT *k;
int *tmp;
byte *fra;
byte *til;
int lgd, vol, i,ofs;
memset(tmpbuf32, 0, mixlgd*sizeof(dword));
k = &intkanaler[0];
for (int ki=0; ki<ANTKANALER; ki++,k++) {
// cerr<<ki<<k->samp<<endl;
if (!k->finito) {
assert(k->samp != NULL);
vol = k->vol * mastervol * k->samp->Volume;
// cout<<"VOL="<<vol<<"{"<<k->vol<<"*"<<mastervol<<"*"<<(int)k->samp->Volume<<"}";
ofs=mixfra-k->start;
// cerr<<"mix(): ofs="<<ofs;
fra = (byte *)k->samp->DataPtr;
tmp = (int *) tmpbuf32;
if (ofs<0) {
lgd=min(k->samp->Length,mixlgd+ofs);
tmp-=ofs;
} else {
lgd=min(k->samp->Length-ofs,mixlgd);
fra+=ofs;
}
assert(lgd>=0);
assert(lgd<=mixlgd);
assert(lgd<=k->samp->Length);
for (i=lgd; i>0; i--) {
// *tmp += *fra * vol;
*tmp += ((int) *fra - 128) * vol;
tmp++;
fra++;
}
if (k->samp->Length <= ofs+mixlgd) k->finito=1;
}
}
// cerr<<"mix dmabuf8"<<dmabuf8<<endl;
til = dmabuf8;
tmp = (int *) tmpbuf32;
// cerr<<"mix til"<<(void*) til<<endl;
for (i=mixlgd; i>0; i--) {
*til = (*tmp >> MIXSKIFTBIT)+128;
/*
vol= ((*tmp)>>MIXSKIFTBIT)+128;
// vol= (*tmp+(128>>MIXSKIFTBIT))>>MIXSKIFTBIT;
*til =vol;
if (vol>255 || vol<0) {
overstyring=vol;
ostmpverdi=*tmp;
}
if (minv > vol) minv = vol;
if (maxv < vol) maxv = vol;
*/
tmp++;
til++;
}
// cout<<"["<<minv<<" "<<maxv<<"]";
// for (i=1; i<10; i++) cerr<<" "<<(int) dmabuf8[i];
// cerr<<endl;
}
static MCI_STATUS_PARMS statpos;
MixTid gettid(void)
{
MixTid t;
t.buf=bufteller+1;/* mellem disse to linier må der helst ikke ske noget */
t.ofs=0;
return t;
}
void DARTopdater(void)
{
/*
int ki;
struct intkanalT *k;
if (overstyring) {
cerr<<"Mix(): overstyring: "<<overstyring<<endl;
for (ki=0,k = &intkanaler[0]; ki<ANTKANALER; ki++,k++)
if (k->samp) cerr<<"kanal "<<ki<<" vol="<<k->vol<<" samp->vol="<<(int) k->samp->Volume<<endl;
cerr<<"mastervol="<<mastervol<<endl<<"*tmp="<<ostmpverdi<<endl;
// exit(-1);
overstyring=0;
}
*/
}
int bufforsinkelse=-1;
long APIENTRY MixerEvent ( ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags )
{
if (ulFlags & MIX_STREAM_ERROR) {
cerr<<"MixerEvent(): MIX_STREAM_ERROR"<<endl;
exit(-1);
} else if (ulFlags == MIX_WRITE_COMPLETE) {
bufteller++;
MixTid t;
t.buf=bufteller;
t.ofs=0;
mix((byte *)MixBuffers[(bufteller+antbuffere-bufforsinkelse)%antbuffere].pBuffer,bufferlgd,mixbuf32,t);
MixSetupParms.pmixWrite( MixSetupParms.ulMixHandle, &MixBuffers[bufteller%antbuffere], 1 );
mmtimeperbuf=pBuffer->ulTime-sidstemmtime;
sidstemmtime=pBuffer->ulTime;
// cerr<<"ulTime="<<pBuffer->ulTime<<" mmtimeperbuf="<<mmtimeperbuf<<endl;
// cerr<<"bc="<<bufteller<<endl;
} else {
cerr<<"MixerEvent(): ulFlags="<<ulFlags<<endl;
exit(-1);
}
return( TRUE );
}
const char *MciError( ULONG ulError )
{
static SZ szBuffer[ STRING_LENGTH ];
if (ulError==0) return "";
rc = mciGetErrorString( ulError, szBuffer, STRING_LENGTH );
dErrorMsg[0] = szBuffer;
cerr<<"MCI error "<<ulError<<": "<<szBuffer<<endl;
return szBuffer;
}
#define BROK_BIT 12
#define BROK_MASKE 0x00000fff
#define MAX_SAMPLE_LGD 1024*100
Sample *resample(Sample *sam, int frek)
{
int i,ink,ofs,v1,v2;
Sample *ret;
ret=new Sample;
*ret=*sam;
int lgd=sam->Length*frek/sam->Rate;
ret->DataPtr= new byte[lgd];
ret->Length=lgd;
ret->Rate=frek;
ink=(sam->Rate<<BROK_BIT)/frek;
byte *s=(byte *) sam->DataPtr;
byte *d=(byte *) ret->DataPtr;
ofs=0;
for (i=lgd;i>0;i--) {
v1=s[ofs>>BROK_BIT];
v2=s[(ofs>>BROK_BIT)+1];
*d=v1+(((v2-v1)*(ofs&BROK_MASKE))>>BROK_BIT);
d++;
ofs+=ink;
}
/*
cout<<endl<<"RESAMPLE:";
for (i=0;i<10;i++) cout<<(int) (((byte *)ret->DataPtr)[lgd/2+i])<<" ";
cout<<endl;
*/
return ret;
}
static Sample indlessamplebuf;
Sample *dImportSample(char *Filename, int Form)
{
MMIOINFO mmioInfo;
MMAUDIOHEADER mmAudioHeader;
HMMIO hmmio;
LONG lBytesRead;
Sample *ind;
if (Form != FORM_WAV) {
dErrorMsg[0]="Only WAV files supported";
return NULL;
}
/* Open the audio file.
*/
memset( &mmioInfo, '\0', sizeof( MMIOINFO ));
mmioInfo.fccIOProc = mmioFOURCC( 'W', 'A', 'V', 'E' );
hmmio = mmioOpen( Filename, &mmioInfo, MMIO_READ | MMIO_DENYNONE );
if (!hmmio) {
dErrorMsg[0]="Could not open a WAV file";
return NULL;
}
/* Get the audio file header.
*/
mmioGetHeader( hmmio,
&mmAudioHeader,
sizeof( MMAUDIOHEADER ),
&lBytesRead,
0,
0);
ind = &indlessamplebuf;
ind->Length = mmAudioHeader.mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes;
ind->Rate = mmAudioHeader.mmXWAVHeader.WAVEHeader.ulSamplesPerSec;
// ind->DataPtr = new byte[ind->Length];
if (ind->Length>MAX_SAMPLE_LGD) {
cerr<<"dImportSample(): sample "<<Filename<<" too big"<<endl;
dErrorMsg[0]="sample too big";
return NULL;
}
ind->Volume=64;
rc = mmioRead ( hmmio,(byte *) ind->DataPtr, ind->Length );
mmioClose( hmmio, 0 );
//mix ind i ret->DataPtr !
ind->LoopStart = ind->Length;
// strncpy(ind->FileName, Filename+20, 13);
strncpy(ind->FileName, Filename+max(0,(int) strlen(Filename)-13), 13);
// cerr<<"MixSetupParms.ulSamplesPerSec="<<MixSetupParms.ulSamplesPerSec<<endl;
// cerr<<"Indlæst "<<Filename<<endl;
// for (int i=0; i<ind->Length; i++) fprintf(stderr,"%3i ",((byte*) ind->DataPtr)[i]);
return resample(ind,MixSetupParms.ulSamplesPerSec);
}
void initDART(void)
{
MCI_AMP_OPEN_PARMS AmpOpenParms;
ULONG ulIndex;
indlessamplebuf.DataPtr=new char[MAX_SAMPLE_LGD];
/* open the mixer device
*/
memset ( &AmpOpenParms, '\0', sizeof ( MCI_AMP_OPEN_PARMS ) );
AmpOpenParms.usDeviceID = ( USHORT ) 0;
AmpOpenParms.pszDeviceType = ( PSZ ) MCI_DEVTYPE_AUDIO_AMPMIX;
rc = mciSendCommand( 0,
MCI_OPEN,
MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
( PVOID ) &AmpOpenParms,
0 );
MciError( rc );
usDeviceID = AmpOpenParms.usDeviceID;
/* Set the MixSetupParms data structure to match the loaded file.
* This is a global that is used to setup the mixer.
*/
memset( &MixSetupParms, '\0', sizeof( MCI_MIXSETUP_PARMS ) );
MixSetupParms.ulBitsPerSample = BPS_8; // eller evt BPS_16 ?
// mmAudioHeader.mmXWAVHeader.WAVEHeader.usBitsPerSample;
MixSetupParms.ulFormatTag = DATATYPE_WAVEFORM;
// mmAudioHeader.mmXWAVHeader.WAVEHeader.usFormatTag;
// MixSetupParms.ulSamplesPerSec = HZ_11025;
// MixSetupParms.ulSamplesPerSec = HZ_22050;
MixSetupParms.ulSamplesPerSec = HZ_44100; // = 44.100
// mmAudioHeader.mmXWAVHeader.WAVEHeader.ulSamplesPerSec;
MixSetupParms.ulChannels = CH_1; // stereo: CH_2
// mmAudioHeader.mmXWAVHeader.WAVEHeader.usChannels;
/* Setup the mixer for playback of wave data
*/
MixSetupParms.ulFormatMode = MCI_PLAY;
MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
MixSetupParms.pmixEvent = MixerEvent;
rc = mciSendCommand( usDeviceID,
MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_INIT,
( PVOID ) &MixSetupParms,
0 );
MciError( rc );
/* Use the suggested buffer size provide by the mixer device
* and the size of the audio file to calculate the required
* number of Amp-Mixer buffers.
* Note: The result is rounded up 1 to make sure we get the
* tail end of the file.
*/
aflus<<"foreslået MixSetupParms.ulBufferSize="<<MixSetupParms.ulBufferSize<<endl;
aflus<<"foreslået MixSetupParms.ulNumBuffers="<<MixSetupParms.ulNumBuffers<<endl;
antbuffere=MixSetupParms.ulNumBuffers=10;
bufferlgd =MixSetupParms.ulBufferSize=1024;
aflus<<"anvendt MixSetupParms.ulBufferSize="<<MixSetupParms.ulBufferSize<<endl;
aflus<<"anvendt MixSetupParms.ulNumBuffers="<<MixSetupParms.ulNumBuffers<<endl;
mixbuf32 = new int[bufferlgd];
/* Set up the BufferParms data structure and allocate
* device buffers from the Amp-Mixer
*/
BufferParms.ulNumBuffers = antbuffere;
BufferParms.ulBufferSize = bufferlgd;
BufferParms.pBufList = MixBuffers;
rc = mciSendCommand( usDeviceID,
MCI_BUFFER,
MCI_WAIT | MCI_ALLOCATE_MEMORY,
( PVOID ) &BufferParms,
0 );
MciError( rc );
for( ulIndex = 0; ulIndex < antbuffere; ulIndex++)
{
memset( MixBuffers[ ulIndex ].pBuffer, '\0', BufferParms.ulBufferSize );
MixBuffers[ ulIndex ].ulBufferLength = BufferParms.ulBufferSize;
}
bufteller = 0;
for (int i=0; i<ANTKANALER; i++) {
intkanaler[i].samp=NULL;
intkanaler[i].vol=0;
intkanaler[i].finito=1;
intkanaler[i].lgd=0;
}
/* Write two buffers to kick off the amp mixer.
*/
rc = MixSetupParms.pmixWrite( MixSetupParms.ulMixHandle,
MixBuffers,
antbuffere);
// MciError(rc);
statpos.ulItem = MCI_STATUS_POSITION; // bruges i getpos
// cerr<<"initDART() slut"<<endl;
}
void exitDART( void )
{
MCI_GENERIC_PARMS GenericParms;
// cerr<<"mastervol = "<<mastervol<<endl;
rc = mciSendCommand( usDeviceID,
MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
( PVOID )&BufferParms,
0 );
MciError( rc );
rc = mciSendCommand( usDeviceID,
MCI_CLOSE,
MCI_WAIT ,
( PVOID )&GenericParms,
0 );
MciError( rc );
delete mixbuf32;
// for (int i=0;i<ANTKANALER;i++) cerr<<"kanal "<<i<<" vol="<<intkanaler[i].vol<<endl;
}
void dPlayVoice(int kanal, Sample *SampPtr)
{
MixTid t=gettid();
intkanaler[kanal].samp = SampPtr;
intkanaler[kanal].start = t;
intkanaler[kanal].vol = 64;
intkanaler[kanal].lgd = SampPtr->Length;
intkanaler[kanal].finito = 0;
// mix((byte *)MixBuffers[t.buf%antbuffere].pBuffer+t.ofs,bufferlgd-t.ofs,mixbuf32,t);
// t.buf++;
// t.ofs=0;
// mix((byte *)MixBuffers[t.buf%antbuffere].pBuffer,bufferlgd,mixbuf32,t);
// cout<<endl<<"dPlayVoice "<<kanal<<" spiller "<<SampPtr->FileName<<" vol="<<intkanaler[kanal].vol<<endl;
}
void dSetVoiceVolume(int kanal, int Volume) { // vol <= 64
intkanaler[kanal].vol = Volume;
// cout<<"dSetVoiceVolume "<<kanal<<" vol="<<Volume<<endl;
}
void dStopVoice(int kanal) {
intkanaler[kanal].finito = 1;
}
void dSetSoundVolume(int Volume) { // vol <= 255
mastervol = Volume;
// cout<<"dSetSoundVolume "<<Volume<<endl;
}
long dGetVoicePos(int Voice)
{
int dif = gettid() - intkanaler[Voice].start;
if (dif > intkanaler[Voice].lgd) return intkanaler[Voice].lgd;
assert(dif>=0);
return dif;
}
void dFreeSample(Sample *SampPtr){
for (int i=0; i<ANTKANALER; i++) {
/* for at være sikker på at den ikke bliver afspillet af en kanal */
intkanaler[i].samp=NULL;
intkanaler[i].vol=0;
intkanaler[i].finito=1;
intkanaler[i].lgd=0;
}
if (SampPtr == NULL) return;
delete SampPtr->DataPtr;
delete SampPtr;
}
#ifndef DEMO
#include <stdio.h>
char getch(void)
{
return _read_kbd(0, 1, 0);
}
int kbdhit(void)
{
return (_read_kbd(0, 0, 0) != -1);
}
void main ( void )
{
Sample *s1, *s2;
initDART();
dSetSoundVolume(255);
// dSetVoiceVolume(0,64);
// dSetVoiceVolume(1,64);
// s1 = dImportSample("forsk\\bye.wav", FORM_WAV);
s1 = dImportSample("d:\\spil\\billy\\samples\\bmove16\\fodtap.wav", FORM_WAV);
s2 = dImportSample("forsk\\hurry3.wav", FORM_WAV);
char ch;
// ch=getchar();
dPlayVoice(0,s2);
int spillet=0;
/*
while (1) {
if (mixenbuffer) {
mixenbuffer=0;
mix((byte *)MixBuffers[bufteller%antbuffere].pBuffer,bufferlgd,mixbuf32,gettid());
}
if (sidstemmtime/3000 > spillet) {
dPlayVoice(1,s1);
spillet++;
}
}
*/
while ((ch=getch()) != 'x') {
DARTopdater();
switch (ch) {
case '1':
dPlayVoice(1,s1);
break;
case '2':
dPlayVoice(2,s2);
break;
case '3':
dPlayVoice(3,s1);
break;
case '4':
dPlayVoice(4,s2);
break;
case '+':
bufforsinkelse++;
break;
case '-':
bufforsinkelse--;
break;
case '?':
cerr<<"forsink: "<<bufforsinkelse<<endl;
break;
}
}
}
#endif