mirror of https://github.com/stella-emu/stella.git
Removed some redundant 'FIXME' and 'TODO' items.
Removed final traces of SpeakJet emulation (the SpeakJet class). It doesn't look this is ever going to be resurrected. Tab completion results in the debugger prompt widget are now sorted. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1993 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
964415508d
commit
5294859e6d
|
@ -31,9 +31,6 @@
|
|||
|
||||
#include "Console.hxx"
|
||||
#include "AtariVox.hxx"
|
||||
#ifdef SPEAKJET_EMULATION
|
||||
#include "SpeakJet.hxx"
|
||||
#endif
|
||||
|
||||
#include "SoundSDL.hxx"
|
||||
|
||||
|
@ -293,8 +290,6 @@ void SoundSDL::set(uInt16 addr, uInt8 value, Int32 cycle)
|
|||
// the sound to "scale" correctly, we have to know the games real frame
|
||||
// rate (e.g., 50 or 60) and the currently emulated frame rate. We use these
|
||||
// values to "scale" the time before the register change occurs.
|
||||
// FIXME - this always results in 1.0, so we don't really need it
|
||||
// delta = delta * (myDisplayFrameRate / myOSystem->frameRate());
|
||||
RegWrite info;
|
||||
info.addr = addr;
|
||||
info.value = value;
|
||||
|
@ -403,27 +398,6 @@ void SoundSDL::callback(void* udata, uInt8* stream, int len)
|
|||
{
|
||||
SoundSDL* sound = (SoundSDL*)udata;
|
||||
sound->processFragment(stream, (Int32)len);
|
||||
|
||||
#ifdef SPEAKJET_EMULATION
|
||||
// cerr << "SoundSDL::callback(): len==" << len << endl;
|
||||
|
||||
// See if we need sound from the AtariVox
|
||||
AtariVox *vox = sound->myOSystem->console().atariVox();
|
||||
if(vox)
|
||||
{
|
||||
// If so, mix 'em together (this is a crappy way to mix audio streams...)
|
||||
uInt8 *s = stream;
|
||||
for(int i=0; i<len/OUTPUT_BUFFER_SIZE; i++)
|
||||
{
|
||||
int count;
|
||||
uInt8 *voxSamples = vox->getSpeakJet()->getSamples(&count);
|
||||
if(!count)
|
||||
break;
|
||||
SDL_MixAudio(s, voxSamples, OUTPUT_BUFFER_SIZE, SDL_MIX_MAXVOLUME);
|
||||
s += OUTPUT_BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -282,9 +282,6 @@ int CartDebug::addressToLine(uInt16 address) const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartDebug::disassemble(uInt16 start, uInt16 lines) const
|
||||
{
|
||||
// if(!(start & 0x1000))
|
||||
// return DebuggerParser::red("Disassembly below 0x1000 not yet supported");
|
||||
// FIXME
|
||||
DisassemblyList list;
|
||||
DiStella distella(list, start, false);
|
||||
|
||||
|
|
|
@ -206,9 +206,6 @@ void Debugger::setConsole(Console* console)
|
|||
// Initialize breakpoints to known state
|
||||
clearAllBreakPoints();
|
||||
clearAllTraps();
|
||||
|
||||
// FIXME - these will probably be removed
|
||||
// loadListFile();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -101,29 +101,7 @@ AudioWidget::~AudioWidget()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||
{
|
||||
/* FIXME - implement this
|
||||
// We simply change the values in the DataGridWidget
|
||||
// It will then send the 'kDGItemDataChangedCmd' signal to change the actual
|
||||
// memory location
|
||||
int addr, value;
|
||||
string buf;
|
||||
|
||||
Debugger& dbg = instance().debugger();
|
||||
TIADebug& tia = dbg.tiaDebug();
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case kDGItemDataChangedCmd:
|
||||
switch(id)
|
||||
{
|
||||
case kNusizP0ID:
|
||||
tia.nusizP0(myNusizP0->getSelectedValue());
|
||||
myNusizP0Text->setEditString(tia.nusizP0String());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
// TODO - implement this
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -52,15 +52,6 @@ void ColorWidget::setColor(int color)
|
|||
setDirty(); draw();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ColorWidget::handleMouseDown(int x, int y, int button, int clickCount)
|
||||
{
|
||||
// TODO - add ColorDialog, which will show all 256 colors in the
|
||||
// TIA palette
|
||||
// if(isEnabled())
|
||||
// parent()->addDialog(myColorDialog);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ColorWidget::drawWidget(bool hilite)
|
||||
{
|
||||
|
|
|
@ -51,7 +51,6 @@ class ColorWidget : public Widget, public CommandSender
|
|||
|
||||
protected:
|
||||
void drawWidget(bool hilite);
|
||||
void handleMouseDown(int x, int y, int button, int clickCount);
|
||||
|
||||
protected:
|
||||
int _color;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "ScrollBarWidget.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
|
@ -36,14 +37,6 @@
|
|||
|
||||
#define PROMPT "> "
|
||||
|
||||
/* TODO:
|
||||
* - it is very inefficient to redraw the full thingy when just one char is added/removed.
|
||||
* Instead, we could just copy the GFX of the blank console (i.e. after the transparent
|
||||
* background is drawn, before any text is drawn). Then using that, it becomes trivial
|
||||
* to erase a single character, do scrolling etc.
|
||||
* - a *lot* of others things, this code is in no way complete and heavily under progress
|
||||
*/
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PromptWidget::PromptWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int w, int h)
|
||||
|
@ -246,7 +239,7 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
|
|||
if(list.size() < 1)
|
||||
break;
|
||||
|
||||
// TODO: sort completions (add sort method to StringList)
|
||||
sort(list.begin(), list.end());
|
||||
completionList = list[0];
|
||||
for(uInt32 i = 1; i < list.size(); ++i)
|
||||
completionList += " " + list[i];
|
||||
|
@ -263,7 +256,7 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
|
|||
if(list.size() < 1)
|
||||
break;
|
||||
|
||||
// TODO: sort completions (add sort method to StringList)
|
||||
sort(list.begin(), list.end());
|
||||
completionList = list[0];
|
||||
for(uInt32 i = 1; i < list.size(); ++i)
|
||||
completionList += " " + list[i];
|
||||
|
@ -852,7 +845,7 @@ void PromptWidget::scrollToCurrent()
|
|||
|
||||
if (line + _linesPerPage <= _scrollLine)
|
||||
{
|
||||
// TODO - this should only occur for loong edit lines, though
|
||||
// TODO - this should only occur for long edit lines, though
|
||||
}
|
||||
else if (line > _scrollLine)
|
||||
{
|
||||
|
|
|
@ -233,7 +233,7 @@ bool CartridgeMC::patch(uInt16 address, uInt8 value)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt8* CartridgeMC::getImage(int& size) const
|
||||
{
|
||||
size = 128 * 1024; // FIXME: keep track of original size
|
||||
size = 128 * 1024;
|
||||
return myImage;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ void CartridgeUA::install(System& system)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeUA::peek(uInt16 address)
|
||||
{
|
||||
// address &= 0x1FFF; TODO - is this needed here?
|
||||
address &= 0x1FFF;
|
||||
|
||||
// Switch banks if necessary
|
||||
switch(address)
|
||||
|
|
|
@ -1,346 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2010 by Bradford W. Mott and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#ifdef SPEAKJET_EMULATION
|
||||
|
||||
#include "SpeakJet.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SpeakJet::SpeakJet()
|
||||
{
|
||||
// Initialize output buffers. Each one points to the next element,
|
||||
// except the last, which points back to the first.
|
||||
SpeechBuffer *first = &outputBuffers[0];
|
||||
SpeechBuffer *last = 0;
|
||||
for(int i=0; i<SPEECH_BUFFERS; i++) {
|
||||
SpeechBuffer *sb = &outputBuffers[i];
|
||||
sb->items = 0;
|
||||
sb->lock = SDL_CreateSemaphore(1);
|
||||
if(last) {
|
||||
last->next = sb;
|
||||
}
|
||||
last = sb;
|
||||
}
|
||||
last->next = first;
|
||||
|
||||
myCurrentOutputBuffer = ourCurrentWriteBuffer = first;
|
||||
ourCurrentWritePosition = 0;
|
||||
|
||||
// Init rsynth library
|
||||
darray_init(&rsynthSamples, sizeof(short), 2048);
|
||||
|
||||
/*
|
||||
rsynth = rsynth_init(samp_rate, mSec_per_frame,
|
||||
rsynth_speaker(F0Hz, gain, Elements),
|
||||
save_sample, flush_samples, &samples);
|
||||
*/
|
||||
rsynth = rsynth_init(31400, 10.0,
|
||||
rsynth_speaker(133.0, 57, Elements),
|
||||
save_sample, flush_samples, &rsynthSamples);
|
||||
spawnThread();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SpeakJet::~SpeakJet()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SpeakJet::spawnThread()
|
||||
{
|
||||
ourInputSemaphore = SDL_CreateSemaphore(1); // 1==unlocked
|
||||
uInt32 sem = SDL_SemValue(ourInputSemaphore);
|
||||
cerr << "before SDL_CreateThread(), sem==" << sem << endl;
|
||||
ourThread = SDL_CreateThread(thread, 0);
|
||||
sem = SDL_SemValue(ourInputSemaphore);
|
||||
cerr << "after SDL_CreateThread(), sem==" << sem << endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int SpeakJet::thread(void *data) {
|
||||
cerr << "rsynth thread spawned" << endl;
|
||||
while(1) {
|
||||
speak();
|
||||
usleep(10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SpeakJet::write(uInt8 code)
|
||||
{
|
||||
cerr << "SpeakJet: output byte " << ((int)(code)) << endl;
|
||||
|
||||
// TODO: clean up this mess.
|
||||
const char *rsynthPhones = xlatePhoneme(code);
|
||||
// cerr << "rsynth: \"" << rsynthPhones << "\"" << endl;
|
||||
int len = strlen(rsynthPhones);
|
||||
|
||||
if(ourInputCount + len + 1 >= INPUT_BUFFER_SIZE) {
|
||||
cerr << "phonemeBuffer is full, dropping" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
uInt32 sem = SDL_SemValue(ourInputSemaphore);
|
||||
// cerr << "write() waiting on semaphore (value " << sem << ")" << endl;
|
||||
SDL_SemWait(ourInputSemaphore);
|
||||
// cerr << "write() got semaphore" << endl;
|
||||
for(int i=0; i<len; i++)
|
||||
phonemeBuffer[ourInputCount++] = rsynthPhones[i];
|
||||
phonemeBuffer[ourInputCount] = '\0';
|
||||
// cerr << "phonemeBuffer contains \"" << phonemeBuffer << "\"" << endl;
|
||||
// cerr << "write() releasing semaphore" << endl;
|
||||
SDL_SemPost(ourInputSemaphore);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SpeakJet::speak()
|
||||
{
|
||||
// TODO: clean up this mess.
|
||||
static char myInput[INPUT_BUFFER_SIZE];
|
||||
|
||||
if(!ourInputCount)
|
||||
return;
|
||||
|
||||
uInt32 sem = SDL_SemValue(ourInputSemaphore);
|
||||
// cerr << "speak() waiting on semaphore (value " << sem << ")" << endl;
|
||||
SDL_SemWait(ourInputSemaphore);
|
||||
// cerr << "speak() got semaphore" << endl;
|
||||
|
||||
// begin locked section
|
||||
|
||||
bool foundSpace = false;
|
||||
for(int i=0; i<ourInputCount; i++)
|
||||
if( (myInput[i] = phonemeBuffer[i]) == ' ')
|
||||
foundSpace = true;
|
||||
|
||||
if(ourInputCount >= INPUT_BUFFER_SIZE - 5)
|
||||
foundSpace = true;
|
||||
|
||||
if(foundSpace)
|
||||
ourInputCount = 0;
|
||||
|
||||
// end locked section
|
||||
// cerr << "speak() releasing semaphore" << endl;
|
||||
SDL_SemPost(ourInputSemaphore);
|
||||
|
||||
if(foundSpace)
|
||||
{
|
||||
// Lock current buffer. save_sample will unlock it when it gets full.
|
||||
SDL_SemWait(ourCurrentWriteBuffer->lock);
|
||||
rsynth_phones(rsynth, myInput, strlen(myInput));
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const char *SpeakJet::xlatePhoneme(uInt8 code)
|
||||
{
|
||||
if(code <= 6)
|
||||
return " ";
|
||||
|
||||
if(code >= 128 && code <= 199)
|
||||
return ourPhonemeTable[ code - 128 ];
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 *SpeakJet::getSamples(int *count) {
|
||||
static uInt8 contents[OUTPUT_BUFFER_SIZE];
|
||||
SDL_sem *lock = myCurrentOutputBuffer->lock;
|
||||
SDL_SemWait(lock);
|
||||
*count = myCurrentOutputBuffer->items;
|
||||
for(int i=0; i<*count; i++)
|
||||
contents[i] = myCurrentOutputBuffer->contents[i];
|
||||
myCurrentOutputBuffer->items = 0;
|
||||
myCurrentOutputBuffer = myCurrentOutputBuffer->next;
|
||||
SDL_SemPost(lock);
|
||||
return contents;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SpeakJet::chipReady()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void *SpeakJet::save_sample(void *user_data,
|
||||
float sample,
|
||||
unsigned nsamp,
|
||||
rsynth_t *rsynth)
|
||||
{
|
||||
static long clip_max;
|
||||
static float peak;
|
||||
short shortSamp;
|
||||
uInt8 output;
|
||||
|
||||
darray_t *buf = (darray_t *) user_data;
|
||||
shortSamp = clip(&clip_max, sample, &peak);
|
||||
darray_short(buf, shortSamp);
|
||||
|
||||
// Convert to 8-bit
|
||||
// output = (uInt8)( (((float)shortSamp) + 32768.0) / 256.0 );
|
||||
double d = shortSamp + 32768.0;
|
||||
output = (uInt8)(d/256.0);
|
||||
// cerr << "Output sample: " << ((int)(output)) << endl;
|
||||
|
||||
// Put in buffer
|
||||
ourCurrentWriteBuffer->contents[ourCurrentWritePosition++] = output;
|
||||
ourCurrentWriteBuffer->items = ourCurrentWritePosition;
|
||||
|
||||
// If buffer is full, unlock it and use the next one.
|
||||
if(ourCurrentWritePosition == OUTPUT_BUFFER_SIZE)
|
||||
{
|
||||
SDL_SemWait(ourCurrentWriteBuffer->next->lock);
|
||||
SDL_SemPost(ourCurrentWriteBuffer->lock);
|
||||
ourCurrentWriteBuffer = ourCurrentWriteBuffer->next;
|
||||
ourCurrentWriteBuffer->items = ourCurrentWritePosition = 0;
|
||||
}
|
||||
return (void *) buf;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void *SpeakJet::flush_samples(void *user_data,
|
||||
unsigned nsamp,
|
||||
rsynth_t *rsynth)
|
||||
{
|
||||
darray_t *buf = (darray_t *) user_data;
|
||||
buf->items = 0;
|
||||
for (;ourCurrentWritePosition < OUTPUT_BUFFER_SIZE; ourCurrentWritePosition++)
|
||||
ourCurrentWriteBuffer->contents[ourCurrentWritePosition] = 0;
|
||||
ourCurrentWritePosition = 0;
|
||||
SDL_SemPost(ourCurrentWriteBuffer->lock);
|
||||
ourCurrentWriteBuffer = ourCurrentWriteBuffer->next; // NOT locked
|
||||
return (void *) buf;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
short SpeakJet::clip(long *clip_max, float input, float *peak)
|
||||
{
|
||||
long temp = (long) input;
|
||||
float isq = input * input;
|
||||
#ifdef PEAK
|
||||
if (isq > *peak)
|
||||
*peak = isq;
|
||||
#else
|
||||
*peak += isq;
|
||||
#endif
|
||||
if (-temp > *clip_max)
|
||||
*clip_max = -temp;
|
||||
if (temp > *clip_max)
|
||||
*clip_max = temp;
|
||||
if (temp < -32767) {
|
||||
temp = -32767;
|
||||
}
|
||||
else if (temp > 32767) {
|
||||
temp = 32767;
|
||||
}
|
||||
return (temp);
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
/*
|
||||
Table of rsynth phonemes, indexed by SpeakJet phoneme code number.
|
||||
Table is offset by 128 bytes (ourPhonemeTable[0] is code #128)
|
||||
see rsynth/phones.def for definitions of rsynth phonemes.
|
||||
We prefix a "'" to the rsynth phoneme for stress or a ","
|
||||
for relax.
|
||||
FIXME: This will need a lot of tweaking, once I get a real
|
||||
SpeakJet to test with.
|
||||
*/
|
||||
|
||||
const char *SpeakJet::ourPhonemeTable[] = {
|
||||
//"rsynth phoneme(s) (phones.def)", // SJ phonemes (p. 16 in SJ manual)
|
||||
"i:", // 128 IY See, Even, Feed
|
||||
"I", // 129 IH Sit, Fix, Pin
|
||||
"eI", // 130 EY Hair, Gate, Beige
|
||||
"E", // 131 EH Met, Check, Red
|
||||
"{", // 132 AY Hat, Fast, Fan
|
||||
"A:", // 133 AX Cotten // maybe "@" instead?
|
||||
"V", // 134 UX Luck, Up, Uncle
|
||||
"Q", // 135 OH Hot, Clock, Fox
|
||||
"A:", // 136 AW Father, Fall
|
||||
"oU", // 137 OW Comb, Over, Hold
|
||||
"U", // 138 UH Book, Could, Should
|
||||
"u:", // 139 UW Food, June
|
||||
"m", // 140 MM Milk, Famous,
|
||||
"n", // 141 NE Nip, Danger, Thin
|
||||
"n", // 142 NO No, Snow, On
|
||||
"N", // 143 NGE Think, Ping
|
||||
"N", // 144 NGO Hung, Song
|
||||
"l", // 145 LE Lake, Alarm, Lapel
|
||||
"l", // 146 LO Clock, Plus, Hello
|
||||
"w", // 147 WW Wool, Sweat
|
||||
"r", // 148 RR Ray, Brain, Over
|
||||
"I@", // 149 IYRR Clear, Hear, Year
|
||||
"e@", // 150 EYRR Hair, Stair, Repair
|
||||
"3:", // 151 AXRR Fir, Bird, Burn
|
||||
"A:", // 152 AWRR Part, Farm, Yarn
|
||||
"Qr", // 153 OWRR Corn, Four, Your [*]
|
||||
"eI", // 154 EYIY Gate, Ate, Ray
|
||||
"aI", // 155 OHIY Mice, Fight, White
|
||||
"OI", // 156 OWIY Boy, Toy, Voice
|
||||
"aI", // 157 OHIH Sky, Five, I
|
||||
"j", // 158 IYEH Yes, Yarn, Million
|
||||
"el", // 159 EHLL Saddle, Angle, Spell [*]
|
||||
"U@", // 160 IYUW Cute, Few // maybe u
|
||||
"aU", // 161 AXUW Brown, Clown, Thousan
|
||||
"U@", // 162 IHWW Two, New, Zoo
|
||||
"aU", // 163 AYWW Our, Ouch, Owl
|
||||
"@U", // 164 OWWW Go, Hello, Snow // maybe "oU"?
|
||||
"dZ", // 165 JH Dodge, Jet, Savage
|
||||
"v", // 166 VV Vest, Even,
|
||||
"z", // 167 ZZ Zoo, Zap
|
||||
"Z", // 168 ZH Azure, Treasure
|
||||
"D", // 169 DH There, That, This
|
||||
"b", // 170 BE Bear, Bird, Beed ???
|
||||
"b", // 171 BO Bone, Book Brown ???
|
||||
"b", // 172 EB Cab, Crib, Web ???
|
||||
"b", // 173 OB Bob, Sub, Tub ???
|
||||
"d", // 174 DE Deep, Date, Divide ???
|
||||
"d", // 175 DO Do, Dust, Dog ???
|
||||
"d", // 176 ED Could, Bird ???
|
||||
"d", // 177 OD Bud, Food ???
|
||||
"g", // 178 GE Get, Gate, Guest, ???
|
||||
"g", // 179 GO Got, Glue, Goo ???
|
||||
"g", // 180 EG Peg, Wig ???
|
||||
"g", // 181 OG Dog, Peg ???
|
||||
"tS", // 182 CH Church, Feature, March
|
||||
"h", // 183 HE Help, Hand, Hair
|
||||
"h", // 184 HO Hoe, Hot, Hug
|
||||
"hw", // 185 WH Who, Whale, White [*]
|
||||
"f", // 186 FF Food, Effort, Off
|
||||
"s", // 187 SE See, Vest, Plus
|
||||
"s", // 188 SO So, Sweat ???
|
||||
"S", // 189 SH Ship, Fiction, Leash
|
||||
"T", // 190 TH Thin, month
|
||||
"t", // 191 TT Part, Little, Sit
|
||||
"t", // 192 TU To, Talk, Ten
|
||||
"ts", // 193 TS Parts, Costs, Robots
|
||||
"k", // 194 KE Can't, Clown, Key
|
||||
"k", // 195 KO Comb, Quick, Fox ???
|
||||
"k", // 196 EK Speak, Task ???
|
||||
"k", // 197 OK Book, Took, October ???
|
||||
"p", // 198 PE People, Computer
|
||||
"p" // 199 PO Paw, Copy ???
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,239 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2010 by Bradford W. Mott and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#ifdef SPEAKJET_EMULATION
|
||||
|
||||
#ifndef SPEAKJET_HXX
|
||||
#define SPEAKJET_HXX
|
||||
|
||||
/**
|
||||
Emulation of the Magnevation SpeakJet.
|
||||
This is the speech synthesizer chip used in the AtariVox.
|
||||
See AtariVox.hxx and .cxx for AtariVox specifics.
|
||||
|
||||
This class doesn't attempt 100% accurate emulation of the SpeakJet,
|
||||
as the chip contains a proprietary algorithm that does some complex
|
||||
modelling (in other words, it doesn't just string samples together).
|
||||
For this emulation, I use a library called rsynth, which does something
|
||||
similar (models the human vocal/nasal tract), but is implemented
|
||||
in a totally different way. You might say I'm emulating the spirit
|
||||
of the SpeakJet, not the letter :)
|
||||
|
||||
Implementation details:
|
||||
|
||||
Both rsynth and the SpeakJet take a stream of phoneme codes and produce
|
||||
audio output.
|
||||
|
||||
My SpeakJet class accepts the SpeakJet phonemes, one at a time, and
|
||||
translates them to rsynth phonemes (which are not quite one-to-one
|
||||
equivalent). As each phoneme is translated, it's added to a phoneme
|
||||
buffer.
|
||||
|
||||
Because of the way rsynth is implemented, it needs a full word's worth
|
||||
of phonemes in its buffer before its speech function is called. This
|
||||
means I'll only call rsynth_phones() when I receive a SpeakJet code that
|
||||
indicates a pause, or end-of-word, or a control code (set parameters
|
||||
or such). This will result in a slight delay (typically, games will
|
||||
send one SJ code per frame).
|
||||
|
||||
Also due to rsynth's implementation, I have to run it in a thread. This
|
||||
is because rsynth_phones() is a monolithic function that needs a string
|
||||
of phonemes, and takes a while to run (for the word "testing", it takes
|
||||
1/4 second on an Athlon 64 @ 1800MHz). We can't have the emulator pause
|
||||
for a quarter second while this happens, so I'll call rsynth_phones()
|
||||
in a separate thread, and have it fill a buffer from which our main
|
||||
thread will pull as much data as it needs. A typical word will be
|
||||
30-40 thousand samples, and we only need fragsize/2 samples at a time.
|
||||
|
||||
As always when using threads, there will be locking in play...
|
||||
|
||||
rsynth's output is always 16-bit samples. This class will have to
|
||||
convert them to 8-bit samples before feeding them to the SDL audio
|
||||
buffer.
|
||||
|
||||
When using the AtariVox, we'll use SDL stereo sound. The regular TIA
|
||||
sound will come out the left channel, and the speech will come out
|
||||
the right. This isn't ideal, but it's the easiest way to mix the two
|
||||
(I don't want to add an SDL_mixer dependency). The real SpeakJet uses a
|
||||
separate speaker from the 2600 (the 2600 TIA sound comes from the TV,
|
||||
the SJ sound comes from a set of PC speakers), so splitting them to
|
||||
the left and right channels isn't unreasonable... However, it means
|
||||
no game can simultaneously use stereo sound and the AtariVox (for now,
|
||||
anyway).
|
||||
|
||||
@author B. Watson
|
||||
@version $Id$
|
||||
*/
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_thread.h>
|
||||
#include "rsynth/rsynth.h"
|
||||
|
||||
struct SpeechBuffer;
|
||||
|
||||
|
||||
enum { INPUT_BUFFER_SIZE = 128 };
|
||||
enum { OUTPUT_BUFFER_SIZE = 128 };
|
||||
enum { SPEECH_BUFFERS = 1024 };
|
||||
static SDL_sem *ourInputSemaphore;
|
||||
static rsynth_t *rsynth;
|
||||
static darray_t rsynthSamples;
|
||||
// phonemeBuffer holds *translated* phonemes (e.g. rsynth phonemes,
|
||||
// not SpeakJet phonemes).
|
||||
static char phonemeBuffer[INPUT_BUFFER_SIZE];
|
||||
// How many bytes are in the input buffer?
|
||||
static uInt16 ourInputCount;
|
||||
|
||||
|
||||
class SpeakJet
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new SpeakJet with given buffer size. We use a circular linked
|
||||
list of fixed size, each node being a buffer of bufferSize 8-bit
|
||||
samples.
|
||||
|
||||
@param bufferSize The size of each output buffer, presumably equal
|
||||
to fragsize/2.
|
||||
*/
|
||||
SpeakJet();
|
||||
|
||||
virtual ~SpeakJet();
|
||||
|
||||
public:
|
||||
/**
|
||||
Writes a SpeakJet phoneme (or other code).
|
||||
These are the codes from page 16 of the Speaket User Manual.
|
||||
Not all codes are emulated. In particular, the non-speech noises
|
||||
(200 thru 254) will be treated as silence. Also, not all the
|
||||
control codes will actually work (will document later).
|
||||
|
||||
@param code The SpeakJet code being written to the emulated chip
|
||||
*/
|
||||
void write(uInt8 code);
|
||||
|
||||
/**
|
||||
Returns a buffer full of 8-bit samples. This should be called every
|
||||
frame or so, or else the older buffers will get overwritten by new
|
||||
data.
|
||||
|
||||
@param count This will be set to the number of samples that are
|
||||
returned. Value ranges from 0 to bufferSize.
|
||||
*/
|
||||
uInt8 *getSamples(int *count);
|
||||
|
||||
/**
|
||||
Returns false if the phonemeBuffer is full, true otherwise.
|
||||
*/
|
||||
bool chipReady();
|
||||
|
||||
private:
|
||||
// function that spawns the rsynth thread
|
||||
void spawnThread();
|
||||
|
||||
// function that the rsynth thread runs...
|
||||
// ...and it has to be a *function*, not a method, because SDL's
|
||||
// written in C. Dammit.
|
||||
static int thread(void *data);
|
||||
|
||||
private:
|
||||
// These functions are called from the rsynth thread context only
|
||||
|
||||
// speak() is our locking wrapper for rsynth_phones()
|
||||
static void speak();
|
||||
|
||||
static void *save_sample(void *user_data,
|
||||
float sample,
|
||||
unsigned nsamp,
|
||||
rsynth_t *rsynth);
|
||||
|
||||
static void *flush_samples(void *user_data,
|
||||
unsigned nsamp,
|
||||
rsynth_t *rsynth);
|
||||
|
||||
static short clip(long *clip_max, float input, float *peak);
|
||||
|
||||
private:
|
||||
|
||||
// True if last code was 20 thru 29
|
||||
bool needParameter;
|
||||
|
||||
static const char *ourPhonemeTable[];
|
||||
|
||||
SDL_Thread *ourThread;
|
||||
|
||||
SpeechBuffer *myCurrentOutputBuffer;
|
||||
|
||||
// We use this semaphore like so:
|
||||
// Main thread locks it initially
|
||||
// Main thread gathers up phonemes, storing in the input buffer,
|
||||
// until it hits a pause/space,
|
||||
// then unlocks the semaphore.
|
||||
// The rsynth thread blocks on the semaphore until the main thread
|
||||
// is done feeding data into the buffer.
|
||||
// When the rsynth thread unblocks, it quickly copies the buffer to
|
||||
// a private buffer, then unlocks the semaphore so the main thread
|
||||
// can re-use the buffer.
|
||||
|
||||
// Note to self: locking decrements the semaphore; unlocking increments
|
||||
// To lock (blocking): SDL_SemWait()
|
||||
// To unlock: SDL_SemPost()
|
||||
|
||||
// Each output buffer also needs its own locking semaphore:
|
||||
// rsynth thread locks each buffer as it fills it, then unlocks it
|
||||
// when it's done, and moves on to the next buffer in the circular
|
||||
// list (blocking if it's locked).
|
||||
|
||||
// When the main thread is ready to play audio, it grabs its idea
|
||||
// of what the next buffer is (blocking if it's locked), locks it, mixes
|
||||
// its contents with the TIA audio data (if it's not an empty buffer),
|
||||
// clears the buffer, then unlocks it.
|
||||
// Note that, if the rsynth thread has been sleeping a while, all
|
||||
// the buffers might be empty.
|
||||
|
||||
// When the rsynth thread runs out of input, it should probably
|
||||
// listen on a condition, so it can be woken up when there's something
|
||||
// to do.
|
||||
|
||||
private:
|
||||
// Convert a SpeakJet phoneme into one or more rsynth phonemes.
|
||||
// Input range is 0 to 255, but not all codes are supported yet.
|
||||
static const char *xlatePhoneme(uInt8 code);
|
||||
|
||||
};
|
||||
|
||||
// Where our output samples go.
|
||||
struct SpeechBuffer
|
||||
{
|
||||
SDL_sem *lock;
|
||||
SpeechBuffer *next;
|
||||
int items;
|
||||
uInt8 contents[OUTPUT_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
// For now, just a static array of them
|
||||
static SpeechBuffer outputBuffers[SPEECH_BUFFERS];
|
||||
|
||||
static SpeechBuffer *ourCurrentWriteBuffer;
|
||||
static uInt8 ourCurrentWritePosition;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -56,7 +56,6 @@ MODULE_OBJS := \
|
|||
src/emucore/SaveKey.o \
|
||||
src/emucore/Serializer.o \
|
||||
src/emucore/Settings.o \
|
||||
src/emucore/SpeakJet.o \
|
||||
src/emucore/Switches.o \
|
||||
src/emucore/StateManager.o \
|
||||
src/emucore/System.o \
|
||||
|
|
|
@ -120,7 +120,7 @@ void TabWidget::disableTab(int tabID)
|
|||
assert(0 <= tabID && tabID < (int)_tabs.size());
|
||||
|
||||
_tabs[tabID].enabled = false;
|
||||
// TODO - alsa disable all widgets belonging to this tab
|
||||
// TODO - also disable all widgets belonging to this tab
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -167,7 +167,6 @@ int const_to_int(char *c) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: store in a map or something
|
||||
// special methods that get e.g. CPU registers
|
||||
CPUDEBUG_INT_METHOD getCpuSpecial(char *c)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue