Fix FreeBoy CPU time bug (#6680)
This commit is contained in:
committed by
Kevin Zander
parent
95cd028e5d
commit
64003fb004
@@ -4,8 +4,8 @@ INCLUDE_DIRECTORIES(game-music-emu/gme)
|
||||
BUILD_PLUGIN(freeboy
|
||||
FreeBoy.cpp
|
||||
FreeBoy.h
|
||||
Gb_Apu_Buffer.cpp
|
||||
Gb_Apu_Buffer.h
|
||||
GbApuWrapper.cpp
|
||||
GbApuWrapper.h
|
||||
game-music-emu/gme/Gb_Apu.cpp
|
||||
game-music-emu/gme/Gb_Apu.h
|
||||
game-music-emu/gme/Gb_Oscs.cpp
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* FreeBoy.cpp - GameBoy papu based instrument
|
||||
*
|
||||
* Copyright (c) 2008 Attila Herman <attila589/at/gmail.com>
|
||||
* Csaba Hruska <csaba.hruska/at/gmail.com>
|
||||
* Csaba Hruska <csaba.hruska/at/gmail.com>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
@@ -23,11 +23,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QDomElement>
|
||||
#include "FreeBoy.h"
|
||||
#include "Gb_Apu_Buffer.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <QDomElement>
|
||||
|
||||
#include "GbApuWrapper.h"
|
||||
#include "base64.h"
|
||||
#include "InstrumentTrack.h"
|
||||
#include "Knob.h"
|
||||
@@ -45,8 +46,11 @@ namespace lmms
|
||||
{
|
||||
|
||||
|
||||
const blip_time_t FRAME_LENGTH = 70224;
|
||||
const long CLOCK_RATE = 4194304;
|
||||
namespace
|
||||
{
|
||||
constexpr blip_time_t FRAME_LENGTH = 70224;
|
||||
constexpr long CLOCK_RATE = 4194304;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -118,9 +122,7 @@ FreeBoyInstrument::FreeBoyInstrument( InstrumentTrack * _instrument_track ) :
|
||||
m_trebleModel( -20.0f, -100.0f, 200.0f, 1.0f, this, tr( "Treble" ) ),
|
||||
m_bassModel( 461.0f, -1.0f, 600.0f, 1.0f, this, tr( "Bass" ) ),
|
||||
|
||||
m_graphModel( 0, 15, 32, this, false, 1 ),
|
||||
|
||||
m_time(0)
|
||||
m_graphModel( 0, 15, 32, this, false, 1 )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -238,189 +240,189 @@ f_cnt_t FreeBoyInstrument::desiredReleaseFrames() const
|
||||
|
||||
|
||||
|
||||
void FreeBoyInstrument::playNote( NotePlayHandle * _n,
|
||||
sampleFrame * _working_buffer )
|
||||
void FreeBoyInstrument::playNote(NotePlayHandle* nph, sampleFrame* workingBuffer)
|
||||
{
|
||||
const f_cnt_t tfp = _n->totalFramesPlayed();
|
||||
const f_cnt_t tfp = nph->totalFramesPlayed();
|
||||
const int samplerate = Engine::audioEngine()->processingSampleRate();
|
||||
const fpp_t frames = _n->framesLeftForCurrentPeriod();
|
||||
const f_cnt_t offset = _n->noteOffset();
|
||||
const fpp_t frames = nph->framesLeftForCurrentPeriod();
|
||||
const f_cnt_t offset = nph->noteOffset();
|
||||
|
||||
int data = 0;
|
||||
int freq = _n->frequency();
|
||||
int freq = nph->frequency();
|
||||
|
||||
if ( tfp == 0 )
|
||||
{
|
||||
auto papu = new Gb_Apu_Buffer();
|
||||
papu->set_sample_rate( samplerate, CLOCK_RATE );
|
||||
auto papu = new GbApuWrapper{};
|
||||
papu->setSampleRate(samplerate, CLOCK_RATE);
|
||||
|
||||
// Master sound circuitry power control
|
||||
papu->write_register( fakeClock(), 0xff26, 0x80 );
|
||||
papu->writeRegister(0xff26, 0x80);
|
||||
|
||||
data = m_ch1VolumeModel.value();
|
||||
data = data<<1;
|
||||
data = data << 1;
|
||||
data += m_ch1VolSweepDirModel.value();
|
||||
data = data<<3;
|
||||
data = data << 3;
|
||||
data += m_ch1SweepStepLengthModel.value();
|
||||
papu->write_register( fakeClock(), 0xff12, data );
|
||||
papu->writeRegister(0xff12, data);
|
||||
|
||||
data = m_ch2VolumeModel.value();
|
||||
data = data<<1;
|
||||
data = data << 1;
|
||||
data += m_ch2VolSweepDirModel.value();
|
||||
data = data<<3;
|
||||
data = data << 3;
|
||||
data += m_ch2SweepStepLengthModel.value();
|
||||
papu->write_register( fakeClock(), 0xff17, data );
|
||||
papu->writeRegister(0xff17, data);
|
||||
|
||||
//channel 4 - noise
|
||||
data = m_ch4VolumeModel.value();
|
||||
data = data<<1;
|
||||
data = data << 1;
|
||||
data += m_ch4VolSweepDirModel.value();
|
||||
data = data<<3;
|
||||
data = data << 3;
|
||||
data += m_ch4SweepStepLengthModel.value();
|
||||
papu->write_register( fakeClock(), 0xff21, data );
|
||||
papu->writeRegister(0xff21, data);
|
||||
|
||||
_n->m_pluginData = papu;
|
||||
nph->m_pluginData = papu;
|
||||
}
|
||||
|
||||
auto papu = static_cast<Gb_Apu_Buffer*>(_n->m_pluginData);
|
||||
auto papu = static_cast<GbApuWrapper*>(nph->m_pluginData);
|
||||
|
||||
papu->treble_eq( m_trebleModel.value() );
|
||||
papu->bass_freq( m_bassModel.value() );
|
||||
papu->trebleEq(m_trebleModel.value());
|
||||
papu->bassFreq(m_bassModel.value());
|
||||
|
||||
//channel 1 - square
|
||||
data = m_ch1SweepTimeModel.value();
|
||||
data = data<<1;
|
||||
data = data << 1;
|
||||
data += m_ch1SweepDirModel.value();
|
||||
data = data << 3;
|
||||
data += m_ch1SweepRtShiftModel.value();
|
||||
papu->write_register( fakeClock(), 0xff10, data );
|
||||
papu->writeRegister(0xff10, data);
|
||||
|
||||
data = m_ch1WavePatternDutyModel.value();
|
||||
data = data<<6;
|
||||
papu->write_register( fakeClock(), 0xff11, data );
|
||||
|
||||
data = data << 6;
|
||||
papu->writeRegister(0xff11, data);
|
||||
|
||||
//channel 2 - square
|
||||
data = m_ch2WavePatternDutyModel.value();
|
||||
data = data<<6;
|
||||
papu->write_register( fakeClock(), 0xff16, data );
|
||||
|
||||
data = data << 6;
|
||||
papu->writeRegister(0xff16, data);
|
||||
|
||||
//channel 3 - wave
|
||||
//data = m_ch3OnModel.value()?128:0;
|
||||
//data = m_ch3OnModel.value() ? 128 : 0;
|
||||
data = 128;
|
||||
papu->write_register( fakeClock(), 0xff1a, data );
|
||||
papu->writeRegister(0xff1a, data);
|
||||
|
||||
auto ch3voldata = std::array{0, 3, 2, 1};
|
||||
data = ch3voldata[(int)m_ch3VolumeModel.value()];
|
||||
data = data<<5;
|
||||
papu->write_register( fakeClock(), 0xff1c, data );
|
||||
|
||||
data = data << 5;
|
||||
papu->writeRegister(0xff1c, data);
|
||||
|
||||
//controls
|
||||
data = m_so1VolumeModel.value();
|
||||
data = data<<4;
|
||||
data = data << 4;
|
||||
data += m_so2VolumeModel.value();
|
||||
papu->write_register( fakeClock(), 0xff24, data );
|
||||
papu->writeRegister(0xff24, data);
|
||||
|
||||
data = m_ch4So2Model.value()?128:0;
|
||||
data += m_ch3So2Model.value()?64:0;
|
||||
data += m_ch2So2Model.value()?32:0;
|
||||
data += m_ch1So2Model.value()?16:0;
|
||||
data += m_ch4So1Model.value()?8:0;
|
||||
data += m_ch3So1Model.value()?4:0;
|
||||
data += m_ch2So1Model.value()?2:0;
|
||||
data += m_ch1So1Model.value()?1:0;
|
||||
papu->write_register( fakeClock(), 0xff25, data );
|
||||
data = m_ch4So2Model.value() ? 128 : 0;
|
||||
data += m_ch3So2Model.value() ? 64 : 0;
|
||||
data += m_ch2So2Model.value() ? 32 : 0;
|
||||
data += m_ch1So2Model.value() ? 16 : 0;
|
||||
data += m_ch4So1Model.value() ? 8 : 0;
|
||||
data += m_ch3So1Model.value() ? 4 : 0;
|
||||
data += m_ch2So1Model.value() ? 2 : 0;
|
||||
data += m_ch1So1Model.value() ? 1 : 0;
|
||||
papu->writeRegister(0xff25, data);
|
||||
|
||||
const float * wpm = m_graphModel.samples();
|
||||
const float* wpm = m_graphModel.samples();
|
||||
|
||||
for( char i=0; i<16; i++ )
|
||||
for (char i = 0; i < 16; ++i)
|
||||
{
|
||||
data = (int)floor(wpm[i*2]) << 4;
|
||||
data += (int)floor(wpm[i*2+1]);
|
||||
papu->write_register( fakeClock(), 0xff30 + i, data );
|
||||
data = static_cast<int>(std::floor(wpm[i * 2])) << 4;
|
||||
data += static_cast<int>(std::floor(wpm[(i * 2) + 1]));
|
||||
papu->writeRegister(0xff30 + i, data);
|
||||
}
|
||||
|
||||
if( ( freq >= 65 ) && ( freq <=4000 ) )
|
||||
if ((freq >= 65) && (freq <= 4000))
|
||||
{
|
||||
int initflag = (tfp==0)?128:0;
|
||||
// Hz = 4194304 / ( ( 2048 - ( 11-bit-freq ) ) << 5 )
|
||||
data = 2048 - ( ( 4194304 / freq )>>5 );
|
||||
if( tfp==0 )
|
||||
int initFlag = (tfp == 0) ? 128 : 0;
|
||||
// Hz = 4194304 / ((2048 - (11-bit-freq)) << 5)
|
||||
data = 2048 - ((4194304 / freq) >> 5);
|
||||
if (tfp == 0)
|
||||
{
|
||||
papu->write_register( fakeClock(), 0xff13, data & 0xff );
|
||||
papu->write_register( fakeClock(), 0xff14, (data>>8) | initflag );
|
||||
papu->writeRegister(0xff13, data & 0xff);
|
||||
papu->writeRegister(0xff14, (data >> 8) | initFlag);
|
||||
}
|
||||
papu->write_register( fakeClock(), 0xff18, data & 0xff );
|
||||
papu->write_register( fakeClock(), 0xff19, (data>>8) | initflag );
|
||||
papu->write_register( fakeClock(), 0xff1d, data & 0xff );
|
||||
papu->write_register( fakeClock(), 0xff1e, (data>>8) | initflag );
|
||||
papu->writeRegister(0xff18, data & 0xff);
|
||||
papu->writeRegister(0xff19, (data >> 8) | initFlag);
|
||||
papu->writeRegister(0xff1d, data & 0xff);
|
||||
papu->writeRegister(0xff1e, (data >> 8) | initFlag);
|
||||
}
|
||||
|
||||
if( tfp == 0 )
|
||||
if (tfp == 0)
|
||||
{
|
||||
//PRNG Frequency = (1048576 Hz / (ratio + 1)) / 2 ^ (shiftclockfreq + 1)
|
||||
char sopt=0;
|
||||
char ropt=1;
|
||||
float fopt = 524288.0 / ( ropt * pow( 2.0, sopt + 1.0 ) );
|
||||
char sopt = 0;
|
||||
char ropt = 1;
|
||||
float fopt = 524288.0 / (ropt * std::pow(2.0, sopt + 1.0));
|
||||
float f;
|
||||
for ( char s=0; s<16; s++ )
|
||||
for ( char r=0; r<8; r++ ) {
|
||||
f = 524288.0 / ( r * pow( 2.0, s + 1.0 ) );
|
||||
if( fabs( freq-fopt ) > fabs( freq-f ) ) {
|
||||
fopt = f;
|
||||
ropt = r;
|
||||
sopt = s;
|
||||
for (char s = 0; s < 16; ++s)
|
||||
{
|
||||
for (char r = 0; r < 8; ++r)
|
||||
{
|
||||
f = 524288.0 / (r * std::pow(2.0, s + 1.0));
|
||||
if (std::fabs(freq - fopt) > std::fabs(freq - f))
|
||||
{
|
||||
fopt = f;
|
||||
ropt = r;
|
||||
sopt = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data = sopt;
|
||||
data = data << 1;
|
||||
data += m_ch4ShiftRegWidthModel.value();
|
||||
data = data << 3;
|
||||
data += ropt;
|
||||
papu->write_register( fakeClock(), 0xff22, data );
|
||||
papu->writeRegister(0xff22, data);
|
||||
|
||||
//channel 4 init
|
||||
papu->write_register( fakeClock(), 0xff23, 128 );
|
||||
papu->writeRegister(0xff23, 128);
|
||||
}
|
||||
|
||||
int const buf_size = 2048;
|
||||
int framesleft = frames;
|
||||
int datalen = 0;
|
||||
auto buf = std::array<blip_sample_t, buf_size * 2>{};
|
||||
while( framesleft > 0 )
|
||||
constexpr int bufSize = 2048;
|
||||
int framesLeft = frames;
|
||||
int dataLen = 0;
|
||||
auto buf = std::array<blip_sample_t, bufSize * 2>{};
|
||||
while (framesLeft > 0)
|
||||
{
|
||||
int avail = papu->samples_avail();
|
||||
if( avail <= 0 )
|
||||
int avail = papu->samplesAvail();
|
||||
if (avail <= 0)
|
||||
{
|
||||
m_time = 0;
|
||||
papu->end_frame(FRAME_LENGTH);
|
||||
avail = papu->samples_avail();
|
||||
papu->endFrame(FRAME_LENGTH);
|
||||
avail = papu->samplesAvail();
|
||||
}
|
||||
datalen = framesleft>avail?avail:framesleft;
|
||||
datalen = datalen>buf_size?buf_size:datalen;
|
||||
dataLen = framesLeft > avail ? avail : framesLeft;
|
||||
dataLen = dataLen > bufSize ? bufSize : dataLen;
|
||||
|
||||
long count = papu->read_samples(buf.data(), datalen * 2) / 2;
|
||||
long count = papu->readSamples(buf.data(), dataLen * 2) / 2;
|
||||
|
||||
for( fpp_t frame = 0; frame < count; ++frame )
|
||||
for (fpp_t frame = 0; frame < count; ++frame)
|
||||
{
|
||||
for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch )
|
||||
for (ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch)
|
||||
{
|
||||
sample_t s = float(buf[frame*2+ch])/32768.0;
|
||||
_working_buffer[frames-framesleft+frame+offset][ch] = s;
|
||||
sample_t s = static_cast<float>(buf[(frame * 2) + ch]) / 32768.0f;
|
||||
workingBuffer[frames - framesLeft + frame + offset][ch] = s;
|
||||
}
|
||||
}
|
||||
framesleft -= count;
|
||||
framesLeft -= count;
|
||||
}
|
||||
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
|
||||
instrumentTrack()->processAudioBuffer(workingBuffer, frames + offset, nph);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FreeBoyInstrument::deleteNotePluginData( NotePlayHandle * _n )
|
||||
void FreeBoyInstrument::deleteNotePluginData(NotePlayHandle* nph)
|
||||
{
|
||||
delete static_cast<Gb_Apu_Buffer *>( _n->m_pluginData );
|
||||
delete static_cast<GbApuWrapper*>(nph->m_pluginData);
|
||||
}
|
||||
|
||||
|
||||
@@ -736,4 +738,4 @@ PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * )
|
||||
}
|
||||
|
||||
|
||||
} // namespace lmms
|
||||
} // namespace lmms
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* FreeBoyInstrument.h - GameBoy papu based instrument
|
||||
* FreeBoy.h - GameBoy papu based instrument
|
||||
*
|
||||
* Copyright (c) 2008 <Attila Herman <attila589/at/gmail.com>
|
||||
* Csaba Hruska <csaba.hruska/at/gmail.com>
|
||||
* Copyright (c) 2008 Attila Herman <attila589/at/gmail.com>
|
||||
* Csaba Hruska <csaba.hruska/at/gmail.com>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
@@ -23,8 +23,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FREEBOY_H
|
||||
#define FREEBOY_H
|
||||
#ifndef LMMS_FREEBOY_H
|
||||
#define LMMS_FREEBOY_H
|
||||
|
||||
#include "AutomatableModel.h"
|
||||
#include "Blip_Buffer.h"
|
||||
@@ -54,10 +54,8 @@ public:
|
||||
FreeBoyInstrument( InstrumentTrack * _instrument_track );
|
||||
~FreeBoyInstrument() override = default;
|
||||
|
||||
void playNote( NotePlayHandle * _n,
|
||||
sampleFrame * _working_buffer ) override;
|
||||
void deleteNotePluginData( NotePlayHandle * _n ) override;
|
||||
|
||||
void playNote(NotePlayHandle* nph, sampleFrame* workingBuffer) override;
|
||||
void deleteNotePluginData(NotePlayHandle* nph) override;
|
||||
|
||||
void saveSettings( QDomDocument & _doc, QDomElement & _parent ) override;
|
||||
void loadSettings( const QDomElement & _this ) override;
|
||||
@@ -112,12 +110,8 @@ private:
|
||||
|
||||
graphModel m_graphModel;
|
||||
|
||||
// Fake CPU timing
|
||||
blip_time_t m_time;
|
||||
blip_time_t fakeClock() { return m_time += 4; }
|
||||
|
||||
friend class gui::FreeBoyInstrumentView;
|
||||
} ;
|
||||
};
|
||||
|
||||
|
||||
namespace gui
|
||||
@@ -172,11 +166,11 @@ private:
|
||||
/*protected slots:
|
||||
void updateKnobHint();
|
||||
void updateKnobToolTip();*/
|
||||
} ;
|
||||
};
|
||||
|
||||
|
||||
} // namespace gui
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
#endif
|
||||
#endif // LMMS_FREEBOY_H
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Gb_Apu_Buffer.cpp - Gb_Apu subclass which allows direct buffer access
|
||||
* GbApuWrapper.cpp - Gb_Apu subclass which allows direct buffer access
|
||||
* Copyright (c) 2017 Tres Finocchiaro <tres.finocchiaro/at/gmail.com>
|
||||
*
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -20,37 +20,45 @@
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
#include "Gb_Apu_Buffer.h"
|
||||
|
||||
#include "GbApuWrapper.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
|
||||
|
||||
void Gb_Apu_Buffer::end_frame(blip_time_t end_time) {
|
||||
Gb_Apu::end_frame(end_time);
|
||||
m_buf.end_frame(end_time);
|
||||
// Sets specified sample rate and clock rate in Stereo_Buffer
|
||||
blargg_err_t GbApuWrapper::setSampleRate(long sampleRate, long clockRate)
|
||||
{
|
||||
Gb_Apu::output(m_buf.center(), m_buf.left(), m_buf.right());
|
||||
m_buf.clock_rate(clockRate);
|
||||
return m_buf.set_sample_rate(sampleRate);
|
||||
}
|
||||
|
||||
// Sets specified sample rate and clock rate in Multi_Buffer
|
||||
blargg_err_t Gb_Apu_Buffer::set_sample_rate(long sample_rate, long clock_rate) {
|
||||
Gb_Apu_Buffer::output(m_buf.center(), m_buf.left(), m_buf.right());
|
||||
m_buf.clock_rate(clock_rate);
|
||||
return m_buf.set_sample_rate(sample_rate);
|
||||
}
|
||||
|
||||
// Wrap Multi_Buffer::samples_avail()
|
||||
long Gb_Apu_Buffer::samples_avail() const {
|
||||
// Wrap Stereo_Buffer::samples_avail()
|
||||
long GbApuWrapper::samplesAvail() const
|
||||
{
|
||||
return m_buf.samples_avail();
|
||||
}
|
||||
|
||||
// Wrap Multi_Buffer::read_samples(...)
|
||||
long Gb_Apu_Buffer::read_samples(sample_t* out, long count) {
|
||||
// Wrap Stereo_Buffer::read_samples(...)
|
||||
long GbApuWrapper::readSamples(blip_sample_t* out, long count)
|
||||
{
|
||||
return m_buf.read_samples(out, count);
|
||||
}
|
||||
|
||||
void Gb_Apu_Buffer::bass_freq(int freq) {
|
||||
// Wrap Stereo_Buffer::bass_freq(...)
|
||||
void GbApuWrapper::bassFreq(int freq)
|
||||
{
|
||||
m_buf.bass_freq(freq);
|
||||
}
|
||||
|
||||
void GbApuWrapper::endFrame(blip_time_t endTime)
|
||||
{
|
||||
m_time = 0;
|
||||
Gb_Apu::end_frame(endTime);
|
||||
m_buf.end_frame(endTime);
|
||||
}
|
||||
|
||||
|
||||
} // namespace lmms
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Gb_Apu_Buffer.cpp - Gb_Apu subclass which allows direct buffer access
|
||||
* GbApuWrapper.h - Gb_Apu subclass which allows direct buffer access
|
||||
* Copyright (c) 2017 Tres Finocchiaro <tres.finocchiaro/at/gmail.com>
|
||||
*
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -20,8 +20,9 @@
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
#ifndef GB_APU_BUFFER_H
|
||||
#define GB_APU_BUFFER_H
|
||||
|
||||
#ifndef LMMS_GB_APU_WRAPPER_H
|
||||
#define LMMS_GB_APU_WRAPPER_H
|
||||
|
||||
#include "Gb_Apu.h"
|
||||
#include "Multi_Buffer.h"
|
||||
@@ -31,25 +32,30 @@ namespace lmms
|
||||
{
|
||||
|
||||
|
||||
class Gb_Apu_Buffer : public Gb_Apu {
|
||||
class GbApuWrapper : private Gb_Apu
|
||||
{
|
||||
MM_OPERATORS
|
||||
public:
|
||||
Gb_Apu_Buffer() = default;
|
||||
~Gb_Apu_Buffer() = default;
|
||||
GbApuWrapper() = default;
|
||||
~GbApuWrapper() = default;
|
||||
|
||||
void end_frame(blip_time_t);
|
||||
blargg_err_t setSampleRate(long sampleRate, long clockRate);
|
||||
void writeRegister(unsigned addr, int data) { Gb_Apu::write_register(fakeClock(), addr, data); }
|
||||
long samplesAvail() const;
|
||||
long readSamples(blip_sample_t* out, long count);
|
||||
void trebleEq(const blip_eq_t& eq) { Gb_Apu::treble_eq(eq); }
|
||||
void bassFreq(int freq);
|
||||
void endFrame(blip_time_t endTime);
|
||||
|
||||
blargg_err_t set_sample_rate(long sample_rate, long clock_rate);
|
||||
long samples_avail() const;
|
||||
using sample_t = blip_sample_t;
|
||||
long read_samples(sample_t* out, long count);
|
||||
void bass_freq(int freq);
|
||||
private:
|
||||
Stereo_Buffer m_buf;
|
||||
|
||||
// Fake CPU timing
|
||||
blip_time_t fakeClock() { return m_time += 4; }
|
||||
blip_time_t m_time = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
#endif
|
||||
|
||||
#endif // LMMS_GB_APU_WRAPPER_H
|
||||
Reference in New Issue
Block a user