203 lines
5.3 KiB
C
203 lines
5.3 KiB
C
/* Copyright 2004 Stephane Dallongeville
|
|
Copyright 2004-2007 Theo Berkau
|
|
Copyright 2006 Guillaume Duhamel
|
|
|
|
This file is part of Yabause.
|
|
|
|
Yabause is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Yabause is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Yabause; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "scsp.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Wave File Output Sound Interface
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int SNDWavInit(void);
|
|
static void SNDWavDeInit(void);
|
|
static int SNDWavReset(void);
|
|
static int SNDWavChangeVideoFormat(int vertfreq);
|
|
static void SNDWavUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples);
|
|
static u32 SNDWavGetAudioSpace(void);
|
|
static void SNDWavMuteAudio(void);
|
|
static void SNDWavUnMuteAudio(void);
|
|
static void SNDWavSetVolume(int volume);
|
|
|
|
SoundInterface_struct SNDWave = {
|
|
SNDCORE_WAV,
|
|
"Wave File Ouput Interface",
|
|
SNDWavInit,
|
|
SNDWavDeInit,
|
|
SNDWavReset,
|
|
SNDWavChangeVideoFormat,
|
|
SNDWavUpdateAudio,
|
|
SNDWavGetAudioSpace,
|
|
SNDWavMuteAudio,
|
|
SNDWavUnMuteAudio,
|
|
SNDWavSetVolume
|
|
};
|
|
|
|
char *wavefilename=NULL;
|
|
static FILE *wavefp;
|
|
|
|
typedef struct {
|
|
char id[4];
|
|
u32 size;
|
|
} chunk_struct;
|
|
|
|
typedef struct {
|
|
chunk_struct riff;
|
|
char rifftype[4];
|
|
} waveheader_struct;
|
|
|
|
typedef struct {
|
|
chunk_struct chunk;
|
|
u16 compress;
|
|
u16 numchan;
|
|
u32 rate;
|
|
u32 bytespersec;
|
|
u16 blockalign;
|
|
u16 bitspersample;
|
|
} fmt_struct;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int SNDWavInit(void)
|
|
{
|
|
waveheader_struct waveheader;
|
|
fmt_struct fmt;
|
|
chunk_struct data;
|
|
IOCheck_struct check;
|
|
|
|
if (wavefilename)
|
|
{
|
|
|
|
if ((wavefp = fopen(wavefilename, "wb")) == NULL)
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
if ((wavefp = fopen("scsp.wav", "wb")) == NULL)
|
|
return -1;
|
|
}
|
|
|
|
// Do wave header
|
|
memcpy(waveheader.riff.id, "RIFF", 4);
|
|
waveheader.riff.size = 0; // we'll fix this after the file is closed
|
|
memcpy(waveheader.rifftype, "WAVE", 4);
|
|
ywrite(&check, (void *)&waveheader, 1, sizeof(waveheader_struct), wavefp);
|
|
|
|
// fmt chunk
|
|
memcpy(fmt.chunk.id, "fmt ", 4);
|
|
fmt.chunk.size = 16; // we'll fix this at the end
|
|
fmt.compress = 1; // PCM
|
|
fmt.numchan = 2; // Stereo
|
|
fmt.rate = 44100;
|
|
fmt.bitspersample = 16;
|
|
fmt.blockalign = fmt.bitspersample / 8 * fmt.numchan;
|
|
fmt.bytespersec = fmt.rate * fmt.blockalign;
|
|
ywrite(&check, (void *)&fmt, 1, sizeof(fmt_struct), wavefp);
|
|
|
|
// data chunk
|
|
memcpy(data.id, "data", 4);
|
|
data.size = 0; // we'll fix this at the end
|
|
ywrite(&check, (void *)&data, 1, sizeof(chunk_struct), wavefp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void SNDWavDeInit(void)
|
|
{
|
|
if (wavefp)
|
|
{
|
|
long length = ftell(wavefp);
|
|
IOCheck_struct check;
|
|
|
|
// Let's fix the riff chunk size and the data chunk size
|
|
fseek(wavefp, sizeof(waveheader_struct)-0x8, SEEK_SET);
|
|
length -= 0x4;
|
|
ywrite(&check, (void *)&length, 1, 4, wavefp);
|
|
|
|
fseek(wavefp, sizeof(waveheader_struct)+sizeof(fmt_struct)+0x4, SEEK_SET);
|
|
length -= sizeof(waveheader_struct)+sizeof(fmt_struct);
|
|
ywrite(&check, (void *)&length, 1, 4, wavefp);
|
|
fclose(wavefp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int SNDWavReset(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int SNDWavChangeVideoFormat(UNUSED int vertfreq)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void SNDWavUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples)
|
|
{
|
|
s16 stereodata16[44100 / 50];
|
|
ScspConvert32uto16s((s32 *)leftchanbuffer, (s32 *)rightchanbuffer, (s16 *)stereodata16, num_samples);
|
|
fwrite((void *)stereodata16, sizeof(s16) * 2, num_samples, wavefp);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static u32 SNDWavGetAudioSpace(void)
|
|
{
|
|
/* A "hack" to get sound core working enough
|
|
* so videos are not "freezing". Values have been
|
|
* found by experiments... I don't have a clue why
|
|
* they are working ^^;
|
|
*/
|
|
static int i = 0;
|
|
i++;
|
|
if (i == 55) {
|
|
i = 0;
|
|
return 85;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void SNDWavMuteAudio(void)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void SNDWavUnMuteAudio(void)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void SNDWavSetVolume(UNUSED int volume)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|