Files
VirtualC64-Core/C64/ReSID.cpp
T
2015-11-18 00:34:41 -06:00

356 lines
11 KiB
C++
Executable File

/*
* (C) 2011 Dirk W. Hoffmann. All rights reserved.
*
* 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
*/
#include "C64.h"
ReSID::ReSID()
{
name = "ReSID";
debug(2, " Creating ReSID at address %p...\n", this);
sid = new SID();
// Register snapshot items
SnapshotItem items[] = {
// Configuration items
{ &chipModel, sizeof(chipModel), KEEP_ON_RESET },
{ &sampleRate, sizeof(sampleRate), KEEP_ON_RESET },
{ &samplingMethod, sizeof(samplingMethod), KEEP_ON_RESET },
{ &cpuFrequency, sizeof(cpuFrequency), KEEP_ON_RESET },
{ &audioFilter, sizeof(audioFilter), KEEP_ON_RESET },
{ &externalAudioFilter, sizeof(externalAudioFilter), KEEP_ON_RESET },
{ &volume, sizeof(volume), KEEP_ON_RESET },
{ &targetVolume, sizeof(targetVolume), KEEP_ON_RESET },
// ReSID state
{ st.sid_register, sizeof(st.sid_register), KEEP_ON_RESET },
{ &st.bus_value, sizeof(st.bus_value), KEEP_ON_RESET },
{ &st.bus_value_ttl, sizeof(st.bus_value_ttl), KEEP_ON_RESET },
{ &st.accumulator[0], sizeof(st.accumulator[0]), KEEP_ON_RESET },
{ &st.accumulator[1], sizeof(st.accumulator[1]), KEEP_ON_RESET },
{ &st.accumulator[2], sizeof(st.accumulator[2]), KEEP_ON_RESET },
{ &st.shift_register[0], sizeof(&st.shift_register[0]), KEEP_ON_RESET },
{ &st.shift_register[1], sizeof(&st.shift_register[1]), KEEP_ON_RESET },
{ &st.shift_register[2], sizeof(&st.shift_register[2]), KEEP_ON_RESET },
{ &st.rate_counter[0], sizeof(st.rate_counter[0]), KEEP_ON_RESET },
{ &st.rate_counter[1], sizeof(st.rate_counter[1]), KEEP_ON_RESET },
{ &st.rate_counter[2], sizeof(st.rate_counter[2]), KEEP_ON_RESET },
{ &st.rate_counter_period[0], sizeof(st.rate_counter_period[0]), KEEP_ON_RESET },
{ &st.rate_counter_period[1], sizeof(st.rate_counter_period[1]), KEEP_ON_RESET },
{ &st.rate_counter_period[2], sizeof(st.rate_counter_period[2]), KEEP_ON_RESET },
{ &st.exponential_counter[0], sizeof(st.exponential_counter[0]), KEEP_ON_RESET },
{ &st.exponential_counter[1], sizeof(st.exponential_counter[1]), KEEP_ON_RESET },
{ &st.exponential_counter[2], sizeof(st.exponential_counter[2]), KEEP_ON_RESET },
{ &st.exponential_counter_period[0],sizeof(st.exponential_counter_period[0]), KEEP_ON_RESET },
{ &st.exponential_counter_period[1],sizeof(st.exponential_counter_period[1]), KEEP_ON_RESET },
{ &st.exponential_counter_period[2],sizeof(st.exponential_counter_period[2]), KEEP_ON_RESET },
{ &st.envelope_counter[0], sizeof(st.envelope_counter[0]), KEEP_ON_RESET },
{ &st.envelope_counter[1], sizeof(st.envelope_counter[1]), KEEP_ON_RESET },
{ &st.envelope_counter[2], sizeof(st.envelope_counter[2]), KEEP_ON_RESET },
{ &st.envelope_state[0], sizeof(st.envelope_state[0]), KEEP_ON_RESET },
{ &st.envelope_state[1], sizeof(st.envelope_state[1]), KEEP_ON_RESET },
{ &st.envelope_state[2], sizeof(st.envelope_state[2]), KEEP_ON_RESET },
{ &st.hold_zero[0], sizeof(st.hold_zero[0]), KEEP_ON_RESET },
{ &st.hold_zero[1], sizeof(st.hold_zero[1]), KEEP_ON_RESET },
{ &st.hold_zero[2], sizeof(st.hold_zero[2]), KEEP_ON_RESET },
{ NULL, 0, 0 }};
registerSnapshotItems(items, sizeof(items));
// Set default values
setChipModel(MOS6581);
cpuFrequency = PAL_CYCLES_PER_FRAME * PAL_REFRESH_RATE;
samplingMethod = SAMPLE_FAST;
sampleRate = 44100;
sid->set_sampling_parameters(cpuFrequency, samplingMethod, sampleRate);
setAudioFilter(false);
setExternalAudioFilter(false);
volume = 100000;
targetVolume = 100000;
}
ReSID::~ReSID()
{
delete sid;
}
void
ReSID::reset()
{
VirtualComponent::reset();
clearRingbuffer();
sid->reset();
}
void
ReSID::setChipModel(chip_model model)
{
switch (model) {
case MOS6581:
debug(2, "Plugging in MOS6581\n");
break;
case MOS8580:
debug(2, "Plugging in MOS8580\n");
break;
default:
warn("Unknown chip model. Using MOS8580\n");
model = MOS8580;
}
chipModel = model;
sid->set_chip_model(model);
}
void
ReSID::setAudioFilter(bool enable)
{
audioFilter = enable;
sid->enable_filter(enable);
}
void
ReSID::setExternalAudioFilter(bool enable)
{
externalAudioFilter = enable;
sid->enable_external_filter(enable);
}
void
ReSID::setSamplingMethod(sampling_method method)
{
switch (method) {
case SAMPLE_FAST:
debug(2, "Using sample method SAMPLE_FAST\n");
break;
case SAMPLE_INTERPOLATE:
debug(2, "Using sample method SAMPLE_INTERPOLATE\n");
break;
case SAMPLE_RESAMPLE_INTERPOLATE:
debug(2, "Using sample method SAMPLE_RESAMPLE_INTERPOLATE\n");
break;
case SAMPLE_RESAMPLE_FAST:
debug(2, "Using sample method SAMPLE_RESAMPLE_FAST\n");
break;
default:
warn("Unknown sample method. Using SAMPLE_FAST\n");
method = SAMPLE_FAST;
}
samplingMethod = method;
sid->set_sampling_parameters(cpuFrequency, samplingMethod, sampleRate);
}
void
ReSID::setSampleRate(uint32_t sr)
{
sampleRate = sr;
sid->set_sampling_parameters(cpuFrequency, samplingMethod, sampleRate);
}
void
ReSID::setClockFrequency(uint32_t frequency)
{
cpuFrequency = frequency;
sid->set_sampling_parameters(cpuFrequency, samplingMethod, sampleRate);
}
void
ReSID::loadFromBuffer(uint8_t **buffer)
{
VirtualComponent::loadFromBuffer(buffer);
// reset();
clearRingbuffer();
/*
setChipModel(chipModel);
setSampleRate(sampleRate);
setSamplingMethod(samplingMethod);
setAudioFilter(audioFilter);
setExternalAudioFilter(externalAudioFilter);
setClockFrequency(cpuFrequency);
*/
// Push state to reSID
sid->write_state(st);
}
void
ReSID::saveToBuffer(uint8_t **buffer)
{
// Pull state from reSID
st = sid->read_state();
VirtualComponent::saveToBuffer(buffer);
}
uint8_t
ReSID::peek(uint16_t addr)
{
return sid->read(addr);
}
void
ReSID::poke(uint16_t addr, uint8_t value)
{
// addr &= 0x1F;
sid->write(addr, value);
}
void
ReSID::execute(int elapsedCycles)
{
short buf[2049];
int buflength = 2048;
int delta_t = elapsedCycles;
int bufindex = 0;
// TODO: Can't we write directly into Core Audios ringbuffer (for Speedup)?
// Let reSID compute some sound samples
while (delta_t) {
bufindex += sid->clock(delta_t, buf + bufindex, buflength - bufindex);
// if (delta_t != 0) debug(2, "delta_t = %d\n", delta_t);
}
// Write samples into ringbuffer (output is silenced in warp mode)
// float volume = c64->getWarp() ? 0.0f : 0.000005f;
for (int i = 0; i < bufindex; i++) {
writeData((float)buf[i]);
}
// fprintf(stderr,"wrote %d samples\n", bufindex);
}
void
ReSID::run()
{
clearRingbuffer();
}
void
ReSID::halt()
{
clearRingbuffer();
}
void
ReSID::clearRingbuffer()
{
debug(4,"Clearing ringbuffer\n");
// Reset ringbuffer contents
for (unsigned i = 0; i < bufferSize; i++) {
ringBuffer[i] = 0.0f;
}
// Reset read pointer and put write pointer somewhat ahead
readPtr = 0;
alignWritePtr();
}
float
ReSID::readData()
{
readDataCnt++;
// Check for buffer underflow
if (readPtr == writePtr)
debug(4, "SID RINGBUFFER UNDERFLOW (%ld)\n", readPtr);
// Read sound sample
float value = ringBuffer[readPtr];
// Adjust volume
if (volume != targetVolume) {
if (volume < targetVolume) {
volume += MIN(volumeDelta, targetVolume - volume);
} else {
volume -= MIN(volumeDelta, volume - targetVolume);
}
}
value = (volume <= 0) ? 0.0f : value * (float)volume / 100000.0f;
// Advance read pointer
readPtr++;
if (readPtr == bufferSize)
readPtr = 0;
return value;
}
inline void
ReSID::writeData(float data)
{
writeDataCnt++;
// Check for buffer overflow
if (readPtr == writePtr) {
debug(4, "SID RINGBUFFER OVERFLOW (%ld)\n", writePtr);
if (!c64->getWarp()) // In real-time mode, we put the write ptr somewhat ahead of the read ptr
alignWritePtr();
else
return; // In warp mode, we don't advance the write ptr to avoid crack noises
}
#if 0
// Adjust volume
if (volume != targetVolume) {
if (volume < targetVolume) {
volume += MIN(volumeDelta, targetVolume - volume);
} else {
volume -= MIN(volumeDelta, volume - targetVolume);
}
}
#endif
// Write sound sample
// float scale = (volume <= 0) ? 0.0f : 0.000005f * (float)volume / 100000.0f;
float scale = 0.000005f;
ringBuffer[writePtr] = data * scale;
// Advance write pointer
writePtr++;
if (writePtr == bufferSize)
writePtr = 0;
}
void
ReSID::dumpState()
{
msg("SID\n");
msg("---\n\n");
msg(" Sample rate : %d\n", sampleRate);
msg(" CPU frequency : %d\n", cpuFrequency);
msg(" Buffer size : %d\n", bufferSize);
msg("\n");
}