Replaced the old OPLL Emu with Nuked-OPLL
This commit is contained in:
parent
9b89b8c21f
commit
d82a8fffb5
8 changed files with 1445 additions and 43 deletions
|
@ -587,6 +587,7 @@
|
||||||
<ClInclude Include="NESHeader.h" />
|
<ClInclude Include="NESHeader.h" />
|
||||||
<ClInclude Include="NotificationManager.h" />
|
<ClInclude Include="NotificationManager.h" />
|
||||||
<ClInclude Include="OpenBusHandler.h" />
|
<ClInclude Include="OpenBusHandler.h" />
|
||||||
|
<ClInclude Include="opll.h" />
|
||||||
<ClInclude Include="PerformanceTracker.h" />
|
<ClInclude Include="PerformanceTracker.h" />
|
||||||
<ClInclude Include="RawVideoFilter.h" />
|
<ClInclude Include="RawVideoFilter.h" />
|
||||||
<ClInclude Include="ResetTxrom.h" />
|
<ClInclude Include="ResetTxrom.h" />
|
||||||
|
@ -1019,6 +1020,7 @@
|
||||||
<ClCompile Include="NsfPpu.cpp" />
|
<ClCompile Include="NsfPpu.cpp" />
|
||||||
<ClCompile Include="OggMixer.cpp" />
|
<ClCompile Include="OggMixer.cpp" />
|
||||||
<ClCompile Include="OggReader.cpp" />
|
<ClCompile Include="OggReader.cpp" />
|
||||||
|
<ClCompile Include="opll.cpp" />
|
||||||
<ClCompile Include="PerformanceTracker.cpp" />
|
<ClCompile Include="PerformanceTracker.cpp" />
|
||||||
<ClCompile Include="PgoUtilities.cpp" />
|
<ClCompile Include="PgoUtilities.cpp" />
|
||||||
<ClCompile Include="RawVideoFilter.cpp" />
|
<ClCompile Include="RawVideoFilter.cpp" />
|
||||||
|
|
|
@ -1514,6 +1514,9 @@
|
||||||
<ClInclude Include="SSGAudio.h">
|
<ClInclude Include="SSGAudio.h">
|
||||||
<Filter>Nes\Mappers</Filter>
|
<Filter>Nes\Mappers</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="opll.h">
|
||||||
|
<Filter>Nes\Mappers\VRC</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="stdafx.cpp">
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
@ -1819,5 +1822,8 @@
|
||||||
<ClCompile Include="ym3438.cpp">
|
<ClCompile Include="ym3438.cpp">
|
||||||
<Filter>Nes\Mappers\EPSG</Filter>
|
<Filter>Nes\Mappers\EPSG</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="opll.cpp">
|
||||||
|
<Filter>Nes\Mappers\VRC</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -397,7 +397,7 @@ void NsfMapper::WriteRegister(uint16_t addr, uint8_t value)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9010: case 0x9030:
|
case 0x9010: case 0x9030:
|
||||||
_vrc7Audio->WriteReg(addr, value);
|
_vrc7Audio->WriteRegister(addr, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,7 +266,7 @@ int16_t SoundMixer::GetOutputVolume(bool forRightChannel)
|
||||||
GetChannelOutput(AudioChannel::Namco163, forRightChannel) * 20 +
|
GetChannelOutput(AudioChannel::Namco163, forRightChannel) * 20 +
|
||||||
GetChannelOutput(AudioChannel::Sunsoft5B, forRightChannel) * 15 +
|
GetChannelOutput(AudioChannel::Sunsoft5B, forRightChannel) * 15 +
|
||||||
GetChannelOutput(AudioChannel::VRC6, forRightChannel) * 75 +
|
GetChannelOutput(AudioChannel::VRC6, forRightChannel) * 75 +
|
||||||
GetChannelOutput(AudioChannel::VRC7, forRightChannel) +
|
GetChannelOutput(AudioChannel::VRC7, forRightChannel) * 2 +
|
||||||
GetChannelOutput(AudioChannel::EPSG_L, forRightChannel) * 15 +
|
GetChannelOutput(AudioChannel::EPSG_L, forRightChannel) * 15 +
|
||||||
GetChannelOutput(AudioChannel::EPSG_R, forRightChannel) * 15
|
GetChannelOutput(AudioChannel::EPSG_R, forRightChannel) * 15
|
||||||
);
|
);
|
||||||
|
|
|
@ -63,7 +63,7 @@ protected:
|
||||||
|
|
||||||
UpdatePrgRamAccess();
|
UpdatePrgRamAccess();
|
||||||
|
|
||||||
_audio->SetMuteAudio((_controlFlags & 0x40) != 0);
|
//_audio->SetMuteAudio((_controlFlags & 0x40) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||||
|
@ -78,7 +78,7 @@ protected:
|
||||||
case 0x8008: SelectPRGPage(1, value & 0x3F); break;
|
case 0x8008: SelectPRGPage(1, value & 0x3F); break;
|
||||||
case 0x9000: SelectPRGPage(2, value & 0x3F); break;
|
case 0x9000: SelectPRGPage(2, value & 0x3F); break;
|
||||||
|
|
||||||
case 0x9010: case 0x9030: _audio->WriteReg(addr, value); break;
|
case 0x9010: case 0x9030: _audio->WriteRegister(addr, value); break;
|
||||||
|
|
||||||
case 0xA000: SelectCHRPage(0, value); break;
|
case 0xA000: SelectCHRPage(0, value); break;
|
||||||
case 0xA008: SelectCHRPage(1, value); break;
|
case 0xA008: SelectCHRPage(1, value); break;
|
||||||
|
|
153
Core/Vrc7Audio.h
153
Core/Vrc7Audio.h
|
@ -1,66 +1,143 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include "Snapshotable.h"
|
||||||
|
#include "APU.h"
|
||||||
#include "BaseExpansionAudio.h"
|
#include "BaseExpansionAudio.h"
|
||||||
|
#include "SSGAudio.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
#include "OpllEmulator.h"
|
|
||||||
|
#include <array>
|
||||||
|
#include "opll.h"
|
||||||
|
|
||||||
class Vrc7Audio : public BaseExpansionAudio
|
class Vrc7Audio : public BaseExpansionAudio
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
unique_ptr<Vrc7Opll::OpllEmulator> _opllEmulator;
|
opll_t _chip;
|
||||||
uint8_t _currentReg;
|
|
||||||
int16_t _previousOutput;
|
|
||||||
double _clockTimer;
|
|
||||||
bool _muted;
|
|
||||||
|
|
||||||
protected:
|
int16_t _lastOutput;
|
||||||
void ClockAudio() override
|
int16_t _currentOutput;
|
||||||
|
|
||||||
|
double _clock;
|
||||||
|
|
||||||
|
static constexpr uint8_t cycleCount = 24;
|
||||||
|
|
||||||
|
struct InputEntry
|
||||||
{
|
{
|
||||||
if(_clockTimer == 0) {
|
uint8_t addr = 0;
|
||||||
_clockTimer = ((double)_console->GetCpu()->GetClockRate(_console->GetModel())) / 49716;
|
uint8_t data = 0;
|
||||||
}
|
uint8_t cycle = 0;
|
||||||
|
uint8_t wrote = 0;
|
||||||
|
};
|
||||||
|
|
||||||
_clockTimer--;
|
static constexpr uint8_t INPUT_BUFFER_SIZE = cycleCount;
|
||||||
if(_clockTimer <= 0) {
|
using InputBuffer = std::array<InputEntry, INPUT_BUFFER_SIZE>;
|
||||||
int16_t output = _opllEmulator->GetOutput();
|
InputBuffer _inputBuffer;
|
||||||
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::VRC7, _muted ? 0 : (output - _previousOutput));
|
|
||||||
_previousOutput = output;
|
void UpdateOutputLevel()
|
||||||
_clockTimer = ((double)_console->GetCpu()->GetClockRate(_console->GetModel())) / 49716;
|
{
|
||||||
}
|
int16_t summedOutput = 0;
|
||||||
|
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::VRC7, _currentOutput - _lastOutput);
|
||||||
|
_lastOutput = _currentOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t GetCurrentCycle() const
|
||||||
|
{
|
||||||
|
return static_cast<uint8_t>(std::floor(_clock)) % cycleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteToChip(uint8_t a, uint8_t d)
|
||||||
|
{
|
||||||
|
const auto cycle = GetCurrentCycle();
|
||||||
|
|
||||||
|
if (_inputBuffer[cycle].wrote)
|
||||||
|
{
|
||||||
|
std::cout << "VRC7 CHIP DOUBLE WRITE" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inputBuffer[cycle] = {
|
||||||
|
a,
|
||||||
|
d,
|
||||||
|
cycle,
|
||||||
|
true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getClockFrequency()
|
||||||
|
{
|
||||||
|
uint32_t vrc7clock = 3579545 / 4;
|
||||||
|
return vrc7clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
void StreamState(bool saving) override
|
void StreamState(bool saving) override
|
||||||
{
|
{
|
||||||
BaseExpansionAudio::StreamState(saving);
|
|
||||||
|
|
||||||
SnapshotInfo opllEmulator{ _opllEmulator.get() };
|
ValueInfo<int16_t> lastOutput{ &_lastOutput };
|
||||||
Stream(opllEmulator, _currentReg, _previousOutput, _clockTimer, _muted);
|
ValueInfo<int16_t> currentOutput{ &_currentOutput };
|
||||||
|
ArrayInfo<InputBuffer> inputBuffer{ &_inputBuffer };
|
||||||
|
ValueInfo<opll_t> chip{ &_chip };
|
||||||
|
ValueInfo<double> clock{ &_clock };
|
||||||
|
Stream(lastOutput, currentOutput, inputBuffer, chip, clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClockAudio() override
|
||||||
|
{
|
||||||
|
|
||||||
|
_clock += getClockFrequency() / (double)_console->GetCpu()->GetClockRate(_console->GetModel());
|
||||||
|
|
||||||
|
while (_clock >= cycleCount)
|
||||||
|
{
|
||||||
|
|
||||||
|
_currentOutput = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (uint8_t cycle = 0; cycle < cycleCount; cycle++)
|
||||||
|
{
|
||||||
|
_clock--;
|
||||||
|
|
||||||
|
int32_t samples[2];
|
||||||
|
OPLL_Clock(&_chip, samples);
|
||||||
|
|
||||||
|
for (uint8_t x = 0; x < 2; x++)
|
||||||
|
{
|
||||||
|
_currentOutput += samples[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& input = _inputBuffer[cycle];
|
||||||
|
if (input.wrote)
|
||||||
|
{
|
||||||
|
input.wrote = false;
|
||||||
|
|
||||||
|
OPLL_Write(&_chip, input.addr, input.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateOutputLevel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Vrc7Audio(shared_ptr<Console> console) : BaseExpansionAudio(console)
|
Vrc7Audio(shared_ptr<Console> console) : BaseExpansionAudio(console)
|
||||||
{
|
{
|
||||||
_previousOutput = 0;
|
_lastOutput = 0;
|
||||||
_currentReg = 0;
|
_currentOutput = 0;
|
||||||
_muted = false;
|
_inputBuffer = {};
|
||||||
_clockTimer = 0;
|
|
||||||
_opllEmulator.reset(new Vrc7Opll::OpllEmulator());
|
_clock = 0;
|
||||||
|
|
||||||
|
OPLL_Reset(&_chip, opll_type_ds1001);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMuteAudio(bool muted)
|
void WriteRegister(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
_muted = muted;
|
switch (addr) {
|
||||||
}
|
case 0x9010:
|
||||||
|
case 0x9030:
|
||||||
|
|
||||||
void WriteReg(uint16_t addr, uint8_t value)
|
const uint8_t a0 = (addr & 0xF030) == 0x9030;
|
||||||
{
|
WriteToChip(a0, value);
|
||||||
switch(addr & 0xF030) {
|
|
||||||
case 0x9010:
|
break;
|
||||||
_currentReg = value;
|
|
||||||
break;
|
|
||||||
case 0x9030:
|
|
||||||
_opllEmulator->WriteReg(_currentReg, value);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
1118
Core/opll.cpp
Normal file
1118
Core/opll.cpp
Normal file
File diff suppressed because it is too large
Load diff
199
Core/opll.h
Normal file
199
Core/opll.h
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Nuke.YKT
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Yamaha YM2413 emulator
|
||||||
|
* Thanks:
|
||||||
|
* siliconpr0n.org(digshadow, John McMaster):
|
||||||
|
* VRC VII decap and die shot.
|
||||||
|
*
|
||||||
|
* version: 1.0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPLL_H
|
||||||
|
#define OPLL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
opll_type_ym2413 = 0x00, /* Yamaha YM2413 */
|
||||||
|
opll_type_ds1001, /* Konami VRC VII */
|
||||||
|
opll_type_ym2413b, /* Yamaha YM2413B */
|
||||||
|
opll_type_ymf281, /* Yamaha YMF281 */
|
||||||
|
opll_type_ymf281b, /* Yamaha YMF281B */
|
||||||
|
opll_type_ym2420, /* Yamaha YM2420 */
|
||||||
|
opll_type_ym2423, /* Yamaha YM2423 */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
opll_patch_1 = 0x00,
|
||||||
|
opll_patch_2,
|
||||||
|
opll_patch_3,
|
||||||
|
opll_patch_4,
|
||||||
|
opll_patch_5,
|
||||||
|
opll_patch_6,
|
||||||
|
opll_patch_7,
|
||||||
|
opll_patch_8,
|
||||||
|
opll_patch_9,
|
||||||
|
opll_patch_10,
|
||||||
|
opll_patch_11,
|
||||||
|
opll_patch_12,
|
||||||
|
opll_patch_13,
|
||||||
|
opll_patch_14,
|
||||||
|
opll_patch_15,
|
||||||
|
opll_patch_drum_0,
|
||||||
|
opll_patch_drum_1,
|
||||||
|
opll_patch_drum_2,
|
||||||
|
opll_patch_drum_3,
|
||||||
|
opll_patch_drum_4,
|
||||||
|
opll_patch_drum_5,
|
||||||
|
opll_patch_max
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t tl;
|
||||||
|
uint8_t dc;
|
||||||
|
uint8_t dm;
|
||||||
|
uint8_t fb;
|
||||||
|
uint8_t am[2];
|
||||||
|
uint8_t vib[2];
|
||||||
|
uint8_t et[2];
|
||||||
|
uint8_t ksr[2];
|
||||||
|
uint8_t multi[2];
|
||||||
|
uint8_t ksl[2];
|
||||||
|
uint8_t ar[2];
|
||||||
|
uint8_t dr[2];
|
||||||
|
uint8_t sl[2];
|
||||||
|
uint8_t rr[2];
|
||||||
|
} opll_patch_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t chip_type;
|
||||||
|
uint32_t cycles;
|
||||||
|
uint32_t slot;
|
||||||
|
const opll_patch_t *patchrom;
|
||||||
|
/* IO */
|
||||||
|
uint8_t write_data;
|
||||||
|
uint8_t write_a;
|
||||||
|
uint8_t write_d;
|
||||||
|
uint8_t write_a_en;
|
||||||
|
uint8_t write_d_en;
|
||||||
|
uint8_t write_fm_address;
|
||||||
|
uint8_t write_fm_data;
|
||||||
|
uint8_t write_mode_address;
|
||||||
|
uint8_t address;
|
||||||
|
uint8_t data;
|
||||||
|
/* Envelope generator */
|
||||||
|
uint8_t eg_counter_state;
|
||||||
|
uint8_t eg_counter_state_prev;
|
||||||
|
uint32_t eg_timer;
|
||||||
|
uint8_t eg_timer_low_lock;
|
||||||
|
uint8_t eg_timer_carry;
|
||||||
|
uint8_t eg_timer_shift;
|
||||||
|
uint8_t eg_timer_shift_lock;
|
||||||
|
uint8_t eg_timer_shift_stop;
|
||||||
|
uint8_t eg_state[18];
|
||||||
|
uint8_t eg_level[18];
|
||||||
|
uint8_t eg_kon;
|
||||||
|
uint32_t eg_dokon;
|
||||||
|
uint8_t eg_off;
|
||||||
|
uint8_t eg_rate;
|
||||||
|
uint8_t eg_maxrate;
|
||||||
|
uint8_t eg_zerorate;
|
||||||
|
uint8_t eg_inc_lo;
|
||||||
|
uint8_t eg_inc_hi;
|
||||||
|
uint8_t eg_rate_hi;
|
||||||
|
uint16_t eg_sl;
|
||||||
|
uint16_t eg_ksltl;
|
||||||
|
uint8_t eg_out;
|
||||||
|
uint8_t eg_silent;
|
||||||
|
/* Phase generator */
|
||||||
|
uint16_t pg_fnum;
|
||||||
|
uint8_t pg_block;
|
||||||
|
uint16_t pg_out;
|
||||||
|
uint32_t pg_inc;
|
||||||
|
uint32_t pg_phase[18];
|
||||||
|
uint32_t pg_phase_next;
|
||||||
|
/* Operator */
|
||||||
|
int16_t op_fb1[9];
|
||||||
|
int16_t op_fb2[9];
|
||||||
|
int16_t op_fbsum;
|
||||||
|
int16_t op_mod;
|
||||||
|
uint8_t op_neg;
|
||||||
|
uint16_t op_logsin;
|
||||||
|
uint16_t op_exp_m;
|
||||||
|
uint16_t op_exp_s;
|
||||||
|
/* Channel */
|
||||||
|
int16_t ch_out;
|
||||||
|
int16_t ch_out_hh;
|
||||||
|
int16_t ch_out_tm;
|
||||||
|
int16_t ch_out_bd;
|
||||||
|
int16_t ch_out_sd;
|
||||||
|
int16_t ch_out_tc;
|
||||||
|
/* LFO */
|
||||||
|
uint16_t lfo_counter;
|
||||||
|
uint8_t lfo_vib_counter;
|
||||||
|
uint16_t lfo_am_counter;
|
||||||
|
uint8_t lfo_am_step;
|
||||||
|
uint8_t lfo_am_dir;
|
||||||
|
uint8_t lfo_am_car;
|
||||||
|
uint8_t lfo_am_out;
|
||||||
|
/* Register set */
|
||||||
|
uint16_t fnum[9];
|
||||||
|
uint8_t block[9];
|
||||||
|
uint8_t kon[9];
|
||||||
|
uint8_t son[9];
|
||||||
|
uint8_t vol[9];
|
||||||
|
uint8_t inst[9];
|
||||||
|
uint8_t rhythm;
|
||||||
|
uint8_t testmode;
|
||||||
|
opll_patch_t patch;
|
||||||
|
uint8_t c_instr;
|
||||||
|
uint8_t c_op;
|
||||||
|
uint8_t c_tl;
|
||||||
|
uint8_t c_dc;
|
||||||
|
uint8_t c_dm;
|
||||||
|
uint8_t c_fb;
|
||||||
|
uint8_t c_am;
|
||||||
|
uint8_t c_vib;
|
||||||
|
uint8_t c_et;
|
||||||
|
uint8_t c_ksr;
|
||||||
|
uint8_t c_ksr_freq;
|
||||||
|
uint8_t c_ksl_freq;
|
||||||
|
uint8_t c_ksl_block;
|
||||||
|
uint8_t c_multi;
|
||||||
|
uint8_t c_ksl;
|
||||||
|
uint8_t c_adrr[3];
|
||||||
|
uint8_t c_sl;
|
||||||
|
uint16_t c_fnum;
|
||||||
|
uint16_t c_block;
|
||||||
|
/* Rhythm mode */
|
||||||
|
int8_t rm_enable;
|
||||||
|
uint32_t rm_noise;
|
||||||
|
uint32_t rm_select;
|
||||||
|
uint8_t rm_hh_bit2;
|
||||||
|
uint8_t rm_hh_bit3;
|
||||||
|
uint8_t rm_hh_bit7;
|
||||||
|
uint8_t rm_hh_bit8;
|
||||||
|
uint8_t rm_tc_bit3;
|
||||||
|
uint8_t rm_tc_bit5;
|
||||||
|
|
||||||
|
int16_t output_m;
|
||||||
|
int16_t output_r;
|
||||||
|
|
||||||
|
} opll_t;
|
||||||
|
|
||||||
|
void OPLL_Reset(opll_t *chip, uint32_t chip_type);
|
||||||
|
void OPLL_Clock(opll_t *chip, int32_t *buffer);
|
||||||
|
void OPLL_Write(opll_t *chip, uint32_t port, uint8_t data);
|
||||||
|
#endif
|
Loading…
Add table
Reference in a new issue