more sound/throttle cleanups and improvements

This commit is contained in:
zeromus 2006-08-25 07:05:55 +00:00
parent 11e0d7ebcf
commit dd126e30e5
6 changed files with 174 additions and 220 deletions

View File

@ -5,8 +5,8 @@
#include "common.h" #include "common.h"
extern PALETTEENTRY color_palette[256]; extern PALETTEENTRY color_palette[256];
extern WAVEFORMATEX wf; //extern WAVEFORMATEX wf;
extern int soundo; //extern int soundo;
#define VIDEO_STREAM 0 #define VIDEO_STREAM 0
#define AUDIO_STREAM 1 #define AUDIO_STREAM 1
@ -306,7 +306,6 @@ int FCEUI_AviBegin(const char* fname)
struct VideoSystemInfo vsi; struct VideoSystemInfo vsi;
BITMAPINFOHEADER bi; BITMAPINFOHEADER bi;
const WAVEFORMATEX* wfex = NULL;
int is_pal; int is_pal;
is_pal=FCEUI_GetCurrentVidSystem(&vsi.start_scanline, &vsi.end_scanline); is_pal=FCEUI_GetCurrentVidSystem(&vsi.start_scanline, &vsi.end_scanline);
@ -321,12 +320,20 @@ int FCEUI_AviBegin(const char* fname)
bi.biHeight = vsi.end_scanline-vsi.start_scanline; bi.biHeight = vsi.end_scanline-vsi.start_scanline;
bi.biSizeImage = 3 * bi.biWidth * bi.biHeight; bi.biSizeImage = 3 * bi.biWidth * bi.biHeight;
if(soundo) //mbg 8/25/06 -- hardcoded stuff for now
wfex = &wf; WAVEFORMATEX wf;
wf.cbSize = sizeof(WAVEFORMATEX);
wf.nAvgBytesPerSec = 44100 * 2;
wf.nBlockAlign = 2;
wf.nChannels = 1;
wf.nSamplesPerSec = 44100;
wf.wBitsPerSample = 16;
wf.wFormatTag = WAVE_FORMAT_PCM;
saved_avi_ext[0]='\0'; saved_avi_ext[0]='\0';
if(!avi_open(fname, &bi, wfex, &vsi)) if(!avi_open(fname, &bi, &wf, &vsi))
{ {
saved_avi_fname[0]='\0'; saved_avi_fname[0]='\0';
return 0; return 0;

View File

@ -305,8 +305,6 @@ void DoPriority(void)
static int changerecursive=0; static int changerecursive=0;
#include "throttle.cpp"
#include "sound.cpp" #include "sound.cpp"
#include "video.cpp" #include "video.cpp"
#include "window.cpp" #include "window.cpp"

View File

@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator /* FCE Ultra - NES/Famicom Emulator
* *
* Copyright notice for this file: * Copyright notice for this file:
* Copyright (C) 2002 Xodnizel * Copyright (C) 2002 Xodnizel and zeromus
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,10 +20,10 @@
#include <list> #include <list>
static int mute=0; /* TODO: add to config? add to GUI. */ /// controls whether playback is muted
static bool mute = false;
/// indicates whether we've been coerced into outputting 8bit audio
int silencer=0; static int bits;
#undef min #undef min
#undef max #undef max
@ -31,6 +31,8 @@ int silencer=0;
OAKRA_Module_OutputDS *dsout; OAKRA_Module_OutputDS *dsout;
//manages a set of small buffers which together work as one large buffer capable of resizing itsself and
//shrinking when a larger buffer is no longer necessary
class BufferSet { class BufferSet {
public: public:
@ -95,14 +97,6 @@ public:
return *(short*)((char*)liveBuffers[buffer]->data+ofs); return *(short*)((char*)liveBuffers[buffer]->data+ofs);
} }
template <class ST>
ST getElementAtIndex(int addr) {
addr *= sizeof(ST); //shorts are 2bytes
int buffer = (addr+offset)>>BufferSizeBits;
int ofs = (addr+offset) & BufferSizeBitmask;
return *(ST*)((char*)liveBuffers[buffer]->data+ofs);
}
//dequeues the specified number of bytes //dequeues the specified number of bytes
void dequeue(int length) { void dequeue(int length) {
offset += length; offset += length;
@ -121,14 +115,14 @@ public:
//not all the bytes you asked for will be locked (no more than one buffer-full) //not all the bytes you asked for will be locked (no more than one buffer-full)
//try again if you didnt get enough. //try again if you didnt get enough.
//returns the number of bytes locked. //returns the number of bytes locked.
int lock(int length, void **ptr) { //int lock(int length, void **ptr) {
int remain = BufferSize-offset; // int remain = BufferSize-offset;
*ptr = (char*)liveBuffers[0]->data + offset; // *ptr = (char*)liveBuffers[0]->data + offset;
if(length<remain) // if(length<remain)
return length; // return length;
else // else
return remain; // return remain;
} //}
void enqueue(int length, void *data) { void enqueue(int length, void *data) {
int todo = length; int todo = length;
@ -155,58 +149,18 @@ public:
} }
}; };
class Player : public OAKRA_Module {
class PlayerBase : public OAKRA_Module {
public:
BufferSet buffers;
int scale;
PlayerBase() {
scale = 256;
}
void receive(int bytes, void *buf) {
dsout->lock();
buffers.enqueue(bytes,buf);
buffers.decay(60);
dsout->unlock();
}
virtual int getSamplesInBuffer() = 0;
void throttle() {
//wait for the buffer to be satisfactorily low before continuing
for(;;) {
dsout->lock();
int remain = getSamplesInBuffer();
dsout->unlock();
if(remain<44100/60) break;
//if(remain<44100*scale/256/60) break; ??
Sleep(1);
}
}
void setScale(int scale) {
dsout->lock();
this->scale = scale;
dsout->unlock();
}
};
template <class ST,int SHIFT,int ZERO>
class Player : public PlayerBase {
public: public:
int cursor; int cursor;
BufferSet buffers;
int getSamplesInBuffer() { return buffers.length>>SHIFT; } int scale;
//not interpolating! someday it will! //not interpolating! someday it will!
int generate(int samples, void *buf) { int generate(int samples, void *buf) {
int incr = 256; int incr = 256;
int bufferSamples = buffers.length>>SHIFT; int bufferSamples = buffers.length>>1;
//if we're we're too far behind, playback faster //if we're we're too far behind, playback faster
if(bufferSamples > 44100*3/60) { if(bufferSamples > 44100*3/60) {
@ -222,28 +176,80 @@ public:
int destSamplesCanGenerate = (bufferSamples<<8) / incr; int destSamplesCanGenerate = (bufferSamples<<8) / incr;
int todo = std::min(destSamplesCanGenerate,samples); int todo = std::min(destSamplesCanGenerate,samples);
ST *sbuf = (ST*)buf; short *sbuf = (short*)buf;
for(int i=0;i<todo;i++) { for(int i=0;i<todo;i++) {
sbuf[i] = buffers.getElementAtIndex<ST>(cursor>>8); sbuf[i] = buffers.getShortAtIndex(cursor>>8);
cursor += incr; cursor += incr;
} }
buffers.dequeue((cursor>>8)<<SHIFT); buffers.dequeue((cursor>>8)<<1);
cursor &= 255; cursor &= 255;
memset(sbuf+todo,ZERO,(samples-todo)<<SHIFT);
//perhaps mute
if(mute) memset(sbuf,0,samples<<1);
else memset(sbuf+todo,0,(samples-todo)<<1);
return samples; return samples;
} }
Player() { void receive(int bytes, void *buf) {
cursor = 0; dsout->lock();
buffers.enqueue(bytes,buf);
buffers.decay(60);
dsout->unlock();
} }
void throttle() {
//wait for the buffer to be satisfactorily low before continuing
for(;;) {
dsout->lock();
int remain = buffers.length>>1;
dsout->unlock();
if(remain<44100/60) break;
//if(remain<44100*scale/256/60) break; ??
Sleep(1);
}
}
void setScale(int scale) {
dsout->lock();
this->scale = scale;
dsout->unlock();
}
Player() {
scale = 256;
cursor = 0;
}
}; };
class ShortPlayer : public Player<short,1,0> {}; //this class just converts the primary 16bit audio stream to 8bit
class BytePlayer : public Player<unsigned char,0,0x80> {}; class Player8 : public OAKRA_Module {
static ShortPlayer *shortPlayer; public:
static BytePlayer *bytePlayer; Player *player;
static PlayerBase *player; Player8(Player *player) { this->player = player; }
int generate(int samples, void *buf) {
int half = samples>>1;
//retrieve first half of 16bit samples
player->generate(half,buf);
//and convert to 8bit
unsigned char *dbuf = (unsigned char*)buf;
short *sbuf = (short*)buf;
for(int i=0;i<half;i++)
dbuf[i] = (sbuf[i]>>8)^0x80;
//now retrieve second half
int remain = samples-half;
short *halfbuf = (short*)alloca(remain<<1);
player->generate(remain,halfbuf);
dbuf += half;
for(int i=0;i<remain;i++)
dbuf[i] = (halfbuf[i]>>8)^0x80;
return samples;
}
};
static Player *player;
static Player8 *player8;
void win_Throttle() { void win_Throttle() {
player->throttle(); player->throttle();
@ -265,25 +271,22 @@ void win_SoundInit(int bits) {
fmt.size = OAKRA_Module::calcSize(fmt); fmt.size = OAKRA_Module::calcSize(fmt);
OAKRA_Voice *voice = dsout->getVoice(fmt); OAKRA_Voice *voice = dsout->getVoice(fmt);
if(bits == 8) player = new Player();
player = bytePlayer = new BytePlayer(); player8 = new Player8(player);
else player = shortPlayer = new ShortPlayer();
dsout->lock(); dsout->lock();
voice->setSource(player); if(bits == 8) voice->setSource(player8);
else voice->setSource(player);
dsout->unlock(); dsout->unlock();
} }
void TrashSound() { void TrashSound() {
delete dsout; if(dsout) delete dsout;
if(player) delete player; if(player) delete player;
dsout = 0;
player = 0; player = 0;
} }
//HACK - aviout is expecting this
WAVEFORMATEX wf;
int bittage; //1 -> 8bit
static int bits;
int InitSound() { int InitSound() {
@ -297,6 +300,7 @@ int InitSound() {
FCEUD_PrintError("DirectSound: 16-bit sound is not supported. Forcing 8-bit sound.");*/ FCEUD_PrintError("DirectSound: 16-bit sound is not supported. Forcing 8-bit sound.");*/
bits = 16; bits = 16;
} }
bits = 8;
win_SoundInit(bits); win_SoundInit(bits);
@ -315,27 +319,16 @@ void win_SoundWriteData(int32 *buffer, int count) {
//todo.. //todo..
// FCEUI_AviSoundUpdate((void*)MBuffer, Count); // FCEUI_AviSoundUpdate((void*)MBuffer, Count);
switch(bits) { void *tempbuf = alloca(2*count);
case 16: { short *sbuf = (short *)tempbuf;
void *tempbuf = alloca(2*count); for(int i=0;i<count;i++)
short *sbuf = (short *)tempbuf; sbuf[i] = buffer[i];
for(int i=0;i<count;i++) player->receive(count*2,tempbuf);
sbuf[i] = buffer[i];
player->receive(count*2,tempbuf);
break;
}
case 8: {
void *tempbuf = alloca(count);
unsigned char *bbuf = (unsigned char *)tempbuf;
for(int i=0;i<count;i++)
bbuf[i] = (buffer[i]>>8)^128;
player->receive(count,tempbuf);
}
}
} }
//--------
//GUI and control APIs
static HWND uug=0; static HWND uug=0;
@ -524,14 +517,13 @@ void FCEUD_SoundToggle(void)
{ {
if(mute) if(mute)
{ {
mute=0; mute = false;
FCEU_DispMessage("Sound mute off."); FCEU_DispMessage("Sound unmuted");
} }
else else
{ {
mute=1; mute = true;
StopSound(); FCEU_DispMessage("Sound muted");
FCEU_DispMessage("Sound mute on.");
} }
} }
@ -543,12 +535,65 @@ void FCEUD_SoundVolumeAdjust(int n)
case 0: soundvolume=100; break; case 0: soundvolume=100; break;
case 1: soundvolume+=10; if(soundvolume>150) soundvolume=150; break; case 1: soundvolume+=10; if(soundvolume>150) soundvolume=150; break;
} }
mute=0; mute = false;
FCEUI_SetSoundVolume(soundvolume); FCEUI_SetSoundVolume(soundvolume);
FCEU_DispMessage("Sound volume %d.", soundvolume); FCEU_DispMessage("Sound volume %d.", soundvolume);
} }
//----------- //-----------
//throttle stuff
//-----------
static uint64 desiredfps;
static int32 fps_scale_table[]=
{ 3, 3, 4, 8, 16, 32, 64, 128, 192, 256, 384, 512, 768, 1024, 2048, 4096, 8192, 16384, 16384};
int32 fps_scale = 256;
static void RefreshThrottleFPS(void)
{
printf("WTF\n");
fflush(stdout);
desiredfps=FCEUI_GetDesiredFPS()>>8;
desiredfps=(desiredfps*fps_scale)>>8;
}
static void IncreaseEmulationSpeed(void)
{
int i;
for(i=1; fps_scale_table[i]<fps_scale; i++)
;
fps_scale = fps_scale_table[i+1];
}
static void DecreaseEmulationSpeed(void)
{
int i;
for(i=1; fps_scale_table[i]<fps_scale; i++)
;
fps_scale = fps_scale_table[i-1];
}
#define fps_table_size (sizeof(fps_scale_table)/sizeof(fps_scale_table[0]))
void FCEUD_SetEmulationSpeed(int cmd)
{
switch(cmd)
{
case EMUSPEED_SLOWEST: fps_scale=fps_scale_table[0]; break;
case EMUSPEED_SLOWER: DecreaseEmulationSpeed(); break;
case EMUSPEED_NORMAL: fps_scale=256; break;
case EMUSPEED_FASTER: IncreaseEmulationSpeed(); break;
case EMUSPEED_FASTEST: fps_scale=fps_scale_table[fps_table_size-1]; break;
default:
return;
}
RefreshThrottleFPS();
FCEU_DispMessage("emulation speed %d%%",(fps_scale*100)>>8);
}
#include "wave.cpp" #include "wave.cpp"

View File

@ -1,84 +0,0 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//http://www.geisswerks.com/ryan/FAQS/timing.html
static uint64 tmethod,tfreq;
static uint64 desiredfps;
static int32 fps_scale_table[]=
{ 3, 3, 4, 8, 16, 32, 64, 128, 192, 256, 384, 512, 768, 1024, 2048, 4096, 8192, 16384, 16384};
int32 fps_scale = 256;
static void RefreshThrottleFPS(void)
{
printf("WTF\n");
fflush(stdout);
desiredfps=FCEUI_GetDesiredFPS()>>8;
desiredfps=(desiredfps*fps_scale)>>8;
}
//mbg todo - these were used by the FPS calculator in video/cpp
// Quick code for internal FPS display.
//uint64 FCEUD_GetTime(void)
//{
// return(GetCurTime()); //this was using queryperformancecounter yuck
//}
//uint64 FCEUD_GetTimeFreq(void)
//{
// return(tfreq>>16);
//}
static void IncreaseEmulationSpeed(void)
{
int i;
for(i=1; fps_scale_table[i]<fps_scale; i++)
;
fps_scale = fps_scale_table[i+1];
}
static void DecreaseEmulationSpeed(void)
{
int i;
for(i=1; fps_scale_table[i]<fps_scale; i++)
;
fps_scale = fps_scale_table[i-1];
}
#define fps_table_size (sizeof(fps_scale_table)/sizeof(fps_scale_table[0]))
void FCEUD_SetEmulationSpeed(int cmd)
{
switch(cmd)
{
case EMUSPEED_SLOWEST: fps_scale=fps_scale_table[0]; break;
case EMUSPEED_SLOWER: DecreaseEmulationSpeed(); break;
case EMUSPEED_NORMAL: fps_scale=256; break;
case EMUSPEED_FASTER: IncreaseEmulationSpeed(); break;
case EMUSPEED_FASTEST: fps_scale=fps_scale_table[fps_table_size-1]; break;
default:
return;
}
RefreshThrottleFPS();
FCEU_DispMessage("emulation speed %d%%",(fps_scale*100)>>8);
}

View File

@ -646,7 +646,7 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
case 322:ConfigTiming();break; case 322:ConfigTiming();break;
case 323:StopSound();ShowNetplayConsole();break; case 323:StopSound();ShowNetplayConsole();break;
case 324:StopSound();ConfigPalette();break; case 324:StopSound();ConfigPalette();break;
case 325:StopSound();ConfigSound();break; case 325:StopSound();ConfigSound();break;
case 326:ConfigVideo();break; case 326:ConfigVideo();break;
case 328:MapInput();break; case 328:MapInput();break;

View File

@ -45,24 +45,12 @@ void FCEU_WriteWaveData(int32 *Buffer, int Count)
if(soundlog) if(soundlog)
wsize+=fwrite(temp,1,Count*sizeof(int16),soundlog); wsize+=fwrite(temp,1,Count*sizeof(int16),soundlog);
#ifdef MSVC #ifdef MSVC
if(FCEUI_AviIsRecording()) if(FCEUI_AviIsRecording())
{ {
extern int bittage; FCEUI_AviSoundUpdate((void*)temp, Count);
if(!bittage) }
{ #endif
//mbg merge 7/17/06 changed to alloca
//int8 temp2[Count];
int8 *temp2 = (int8*)alloca(Count);
int P;
for(P=0;P<Count;P++)
*(((uint8*)temp2)+P)=((int8)(temp[P]>>8))^128;
FCEUI_AviSoundUpdate((void*)temp2, Count);
}
else
FCEUI_AviSoundUpdate((void*)temp, Count);
}
#endif
} }
int FCEUI_EndWaveRecord(void) int FCEUI_EndWaveRecord(void)