1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-04-07 01:38:25 +00:00

Continues doing away with the attempt heavily to interleave the OPLL and OPL2, creating a new OPLL class.

This commit is contained in:
Thomas Harte 2020-05-04 21:14:51 -04:00
parent e929d5d819
commit 386a7ca442
9 changed files with 420 additions and 70 deletions

View File

@ -11,6 +11,7 @@
#include <optional>
#include <functional>
#include "LowFrequencyOscillator.hpp"
namespace Yamaha {
namespace OPL {

View File

@ -0,0 +1,40 @@
//
// OPLBase.hpp
// Clock Signal
//
// Created by Thomas Harte on 03/05/2020.
// Copyright © 2020 Thomas Harte. All rights reserved.
//
#ifndef OPLBase_h
#define OPLBase_h
#include "../../../Outputs/Speaker/Implementation/SampleSource.hpp"
#include "../../../Concurrency/AsyncTaskQueue.hpp"
namespace Yamaha {
namespace OPL {
template <typename Child> class OPLBase: public ::Outputs::Speaker::SampleSource {
public:
void write(uint16_t address, uint8_t value) {
if(address & 1) {
static_cast<Child *>(this)->write_register(selected_register_, value);
} else {
selected_register_ = value;
}
}
protected:
OPLBase(Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_(task_queue) {}
Concurrency::DeferringAsyncTaskQueue &task_queue_;
private:
uint8_t selected_register_ = 0;
};
}
}
#endif /* OPLBase_h */

View File

@ -15,12 +15,12 @@
namespace Yamaha {
namespace OPL {
enum class Waveform {
Sine, HalfSine, AbsSine, PulseSine
};
template <int phase_precision> class WaveformGenerator {
public:
enum class Waveform {
Sine, HalfSine, AbsSine, PulseSine
};
/*!
@returns The output of waveform @c form at [integral] phase @c phase.
*/

View File

@ -18,6 +18,8 @@
using namespace Yamaha::OPL;
/*
template <typename Child>
OPLBase<Child>::OPLBase(Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_(task_queue) {}
@ -79,43 +81,42 @@ void OPLL::get_samples(std::size_t number_of_samples, std::int16_t *target) {
audio_offset_ = (audio_offset_ + 1) % update_period;
}
/* // Fill in any leftover from the previous session.
if(audio_offset_) {
while(audio_offset_ < update_period && number_of_samples) {
*target = int16_t(channels_[audio_offset_ / channel_output_period].level);
++target;
++audio_offset_;
--number_of_samples;
}
audio_offset_ = 0;
}
// End now if that provided everything that was asked for.
if(!number_of_samples) return;
int total_updates = int(number_of_samples) / update_period;
number_of_samples %= size_t(update_period);
audio_offset_ = int(number_of_samples);
while(total_updates--) {
update_all_chanels();
for(int c = 0; c < update_period; ++c) {
*target = int16_t(channels_[c / channel_output_period].level);
++target;
}
}
// If there are any other spots remaining, fill them.
if(number_of_samples) {
update_all_chanels();
for(int c = 0; c < int(number_of_samples); ++c) {
*target = int16_t(channels_[c / channel_output_period].level);
++target;
}
}*/
// // Fill in any leftover from the previous session.
// if(audio_offset_) {
// while(audio_offset_ < update_period && number_of_samples) {
// *target = int16_t(channels_[audio_offset_ / channel_output_period].level);
// ++target;
// ++audio_offset_;
// --number_of_samples;
// }
// audio_offset_ = 0;
// }
//
// // End now if that provided everything that was asked for.
// if(!number_of_samples) return;
//
// int total_updates = int(number_of_samples) / update_period;
// number_of_samples %= size_t(update_period);
// audio_offset_ = int(number_of_samples);
//
// while(total_updates--) {
// update_all_chanels();
//
// for(int c = 0; c < update_period; ++c) {
// *target = int16_t(channels_[c / channel_output_period].level);
// ++target;
// }
// }
//
// // If there are any other spots remaining, fill them.
// if(number_of_samples) {
// update_all_chanels();
//
// for(int c = 0; c < int(number_of_samples); ++c) {
// *target = int16_t(channels_[c / channel_output_period].level);
// ++target;
// }
// }
}
void OPLL::set_sample_volume_range(std::int16_t range) {
@ -274,9 +275,9 @@ void OPLL::update_all_chanels() {
#undef VOLUME
}
/*
template <Personality personality>
void OPL2<personality>::get_samples(std::size_t number_of_samples, std::int16_t *target) {
//template <Personality personality>
//void OPL2<personality>::get_samples(std::size_t number_of_samples, std::int16_t *target) {
// TODO.
// out = exp(logsin(phase2 + exp(logsin(phase1) + gain1)) + gain2)
@ -301,9 +302,9 @@ void OPL2<personality>::get_samples(std::size_t number_of_samples, std::int16_t
// Tom tom, using operator 14,
// Cymbal, using operator 17; and
// Symbol, using operator 13.
}
//}
*/
void OPL2::write_register(uint8_t address, uint8_t value) {
@ -393,3 +394,5 @@ uint8_t OPL2::read(uint16_t address) {
// b5 = timer 2 flag
return 0xff;
}
*/

View File

@ -20,24 +20,7 @@
namespace Yamaha {
namespace OPL {
template <typename Child> class OPLBase: public ::Outputs::Speaker::SampleSource {
public:
void write(uint16_t address, uint8_t value);
protected:
OPLBase(Concurrency::DeferringAsyncTaskQueue &task_queue);
Concurrency::DeferringAsyncTaskQueue &task_queue_;
LowFrequencyOscillator oscillator_;
uint8_t depth_rhythm_control_;
uint8_t csm_keyboard_split_;
bool waveform_enable_;
private:
uint8_t selected_register_ = 0;
};
/*
struct OPL2: public OPLBase<OPL2> {
public:
// Creates a new OPL2.
@ -132,7 +115,7 @@ struct OPLL: public OPLBase<OPLL> {
int audio_offset_ = 0;
std::atomic<int> total_volume_;
};
};*/
}
}

215
Components/OPL2/OPLL.cpp Normal file
View File

@ -0,0 +1,215 @@
//
// OPLL.cpp
// Clock Signal
//
// Created by Thomas Harte on 03/05/2020.
// Copyright © 2020 Thomas Harte. All rights reserved.
//
#include "OPLL.hpp"
#include <cassert>
using namespace Yamaha::OPL;
OPLL::OPLL(Concurrency::DeferringAsyncTaskQueue &task_queue, int audio_divider, bool is_vrc7):
OPLBase(task_queue), audio_divider_(audio_divider), is_vrc7_(is_vrc7) {
// Due to the way that sound mixing works on the OPLL, the audio divider may not
// be larger than 4.
assert(audio_divider <= 4);
// Set up proper damping management.
for(int c = 0; c < 9; ++c) {
envelope_generators_[c].set_should_damp([this, c] {
// Propagate attack mode to the modulator, and reset both phases.
envelope_generators_[c + 9].set_key_on(true);
phase_generators_[c + 0].reset();
phase_generators_[c + 9].reset();
});
}
}
// MARK: - Machine-facing programmatic input.
void OPLL::write_register(uint8_t address, uint8_t value) {
// The OPLL doesn't have timers or other non-audio functions, so all writes
// go to the audio queue.
task_queue_.defer([this, address, value] {
// The first 8 locations are used to define the custom instrument, and have
// exactly the same format as the patch set arrays at the head of this file.
if(address < 8) {
custom_instrument_[address] = value;
// Update all channels that refer to instrument 0.
for(int c = 0; c < 9; ++c) {
if(!channels_[c].instrument) {
install_instrument(c);
}
}
return;
}
// Register 0xe enables or disables rhythm mode and contains the
// percussion key-on bits.
if(address == 0xe) {
rhythm_mode_enabled_ = value & 0x20;
rhythm_generators_[0].set_key_on(value & 0x01);
rhythm_generators_[1].set_key_on(value & 0x02);
rhythm_generators_[2].set_key_on(value & 0x04);
rhythm_generators_[3].set_key_on(value & 0x08);
rhythm_generators_[4].set_key_on(value & 0x10);
return;
}
// That leaves only per-channel selections, for which the addressing
// is completely orthogonal; check that a valid channel is being requested.
const auto index = address & 0xf;
if(index > 8) return;
switch(address & 0xf0) {
default: break;
// Address 1x sets the low 8 bits of the period for channel x.
case 0x10:
channels_[index].period = (channels_[index].period & ~0xff) | value;
set_channel_period(index);
return;
// Address 2x Sets the octave and a single bit of the frequency, as well
// as setting key on and sustain mode.
case 0x20:
channels_[index].period = (channels_[index].period & 0xff) | (value & 1);
channels_[index].octave = (value >> 1) & 7;
set_channel_period(index);
// In this implementation the first 9 envelope generators are for
// channel carriers, and their will_attack callback is used to trigger
// key-on for modulators. But key-off needs to be set to both envelope
// generators now.
if(value & 0x10) {
envelope_generators_[index].set_key_on(true);
} else {
envelope_generators_[index + 0].set_key_on(false);
envelope_generators_[index + 9].set_key_on(false);
}
// Set sustain bit to both the relevant operators.
channels_[index].use_sustain = value & 0x20;
set_use_sustain(index);
return;
// Address 3x selects the instrument and attenuation for a channel;
// in rhythm mode some of the nibbles that ordinarily identify instruments
// instead nominate additional attenuations. This code reads those back
// from the stored instrument values.
case 0x30:
channels_[index].instrument = value >> 4;
channels_[index].attenuation = value >> 4;
install_instrument(index);
return;
}
});
}
void OPLL::set_channel_period(int channel) {
phase_generators_[channel + 0].set_period(channels_[channel].period, channels_[channel].octave);
phase_generators_[channel + 9].set_period(channels_[channel].period, channels_[channel].octave);
key_level_scalers_[channel + 0].set_period(channels_[channel].period, channels_[channel].octave);
key_level_scalers_[channel + 9].set_period(channels_[channel].period, channels_[channel].octave);
}
const uint8_t *OPLL::instrument_definition(int instrument) {
// Instrument 0 is the custom instrument.
if(!instrument) return custom_instrument_;
// Instruments other than 0 are taken from the fixed set.
const int index = (instrument - 1) * 8;
return is_vrc7_ ? &vrc7_patch_set[index] : &opll_patch_set[index];
}
void OPLL::install_instrument(int channel) {
auto &carrier_envelope = envelope_generators_[channel + 0];
auto &carrier_phase = phase_generators_[channel + 0];
auto &carrier_scaler = key_level_scalers_[channel + 0];
auto &modulator_envelope = envelope_generators_[channel + 9];
auto &modulator_phase = phase_generators_[channel + 9];
auto &modulator_scaler = key_level_scalers_[channel + 9];
const uint8_t *const instrument = instrument_definition(channels_[channel].instrument);
// Bytes 0 (modulator) and 1 (carrier):
//
// b0-b3: multiplier;
// b4: key-scale rate enable;
// b5: sustain-level enable;
// b6: vibrato enable;
// b7: tremolo enable.
modulator_phase.set_multiple(instrument[0] & 0xf);
channels_[channel].modulator_key_rate_scale_multiplier = (instrument[0] >> 4) & 1;
modulator_phase.set_vibrato_enabled(instrument[0] & 0x40);
modulator_envelope.set_tremolo_enabled(instrument[0] & 0x80);
carrier_phase.set_multiple(instrument[1] & 0xf);
channels_[channel].carrier_key_rate_scale_multiplier = (instrument[1] >> 4) & 1;
carrier_phase.set_vibrato_enabled(instrument[1] & 0x40);
carrier_envelope.set_tremolo_enabled(instrument[1] & 0x80);
// Pass off bit 5.
set_use_sustain(channel);
// Byte 2:
//
// b0b5: modulator attenuation;
// b6b7: modulator key-scale level.
modulator_scaler.set_key_scaling_level(instrument[3] >> 6);
channels_[channel].modulator_attenuation = instrument[2] & 0x3f;
// Byte 3:
//
// b0b2: modulator feedback level;
// b3: modulator waveform selection;
// b4: carrier waveform selection;
// b5: [unused]
// b6b7: carrier key-scale level.
channels_[channel].modulator_feedback = instrument[3] & 7;
channels_[channel].modulator_waveform = Waveform((instrument[3] >> 3) & 1);
channels_[channel].carrier_waveform = Waveform((instrument[3] >> 4) & 1);
carrier_scaler.set_key_scaling_level(instrument[3] >> 6);
// Bytes 4 (modulator) and 5 (carrier):
//
// b0b3: decay rate;
// b4b7: attack rate.
modulator_envelope.set_decay_rate(instrument[4] & 0xf);
modulator_envelope.set_attack_rate(instrument[4] >> 4);
carrier_envelope.set_decay_rate(instrument[5] & 0xf);
carrier_envelope.set_attack_rate(instrument[5] >> 4);
// Bytes 6 (modulator) and 7 (carrier):
//
// b0b3: release rate;
// b4b7: sustain level.
modulator_envelope.set_release_rate(instrument[6] & 0xf);
modulator_envelope.set_sustain_level(instrument[6] >> 4);
carrier_envelope.set_release_rate(instrument[7] & 0xf);
carrier_envelope.set_release_rate(instrument[7] >> 4);
}
void OPLL::set_use_sustain(int channel) {
const uint8_t *const instrument = instrument_definition(channels_[channel].instrument);
envelope_generators_[channel + 0].set_sustain_level((instrument[1] & 0x20) || channels_[channel].use_sustain);
envelope_generators_[channel + 9].set_sustain_level((instrument[0] & 0x20) || channels_[channel].use_sustain);
}
// MARK: - Output generation.
void OPLL::set_sample_volume_range(std::int16_t range) {
total_volume_ = range;
}
void OPLL::get_samples(std::size_t number_of_samples, std::int16_t *target) {
// TODO.
}

102
Components/OPL2/OPLL.hpp Normal file
View File

@ -0,0 +1,102 @@
//
// OPLL.hpp
// Clock Signal
//
// Created by Thomas Harte on 03/05/2020.
// Copyright © 2020 Thomas Harte. All rights reserved.
//
#ifndef OPLL_hpp
#define OPLL_hpp
#include "Implementation/OPLBase.hpp"
#include "Implementation/EnvelopeGenerator.hpp"
#include "Implementation/KeyLevelScaler.hpp"
#include "Implementation/PhaseGenerator.hpp"
#include "Implementation/LowFrequencyOscillator.hpp"
#include "Implementation/WaveformGenerator.hpp"
#include <atomic>
namespace Yamaha {
namespace OPL {
class OPLL: public OPLBase<OPLL> {
public:
/// Creates a new OPLL or VRC7.
OPLL(Concurrency::DeferringAsyncTaskQueue &task_queue, int audio_divider = 1, bool is_vrc7 = false);
/// As per ::SampleSource; provides audio output.
void get_samples(std::size_t number_of_samples, std::int16_t *target);
void set_sample_volume_range(std::int16_t range);
/// Reads from the OPL.
uint8_t read(uint16_t address);
private:
friend OPLBase<OPLL>;
void write_register(uint8_t address, uint8_t value);
int audio_divider_ = 0;
std::atomic<int> total_volume_;
static constexpr int period_precision = 9;
static constexpr int envelope_precision = 9;
// Standard melodic phase and envelope generators.
PhaseGenerator<period_precision> phase_generators_[18];
EnvelopeGenerator<envelope_precision, period_precision> envelope_generators_[18];
KeyLevelScaler<period_precision> key_level_scalers_[18];
// Dedicated rhythm envelope generators and attenuations.
EnvelopeGenerator<envelope_precision, period_precision> rhythm_generators_[5];
int rhythm_attenuations_[5];
// Channel specifications.
struct Channel {
int octave = 0;
int period = 0;
int instrument = 0;
int attenuation = 0;
int modulator_attenuation = 0;
Waveform carrier_waveform = Waveform::Sine;
Waveform modulator_waveform = Waveform::Sine;
int carrier_key_rate_scale_multiplier = 0;
int modulator_key_rate_scale_multiplier = 0;
int modulator_feedback = 0;
bool use_sustain = false;
} channels_[9];
// The low-frequency oscillator.
LowFrequencyOscillator oscillator_;
bool rhythm_mode_enabled_ = false;
bool is_vrc7_ = false;
// Contains the current configuration of the custom instrument.
uint8_t custom_instrument_[8];
// Helpers to push per-channel information.
/// Pushes the current octave and period to channel @c channel.
void set_channel_period(int channel);
/// Installs the appropriate instrument on channel @c channel.
void install_instrument(int channel);
/// Sets whether the sustain level is used for channel @c channel based on its current instrument
/// and the user's selection.
void set_use_sustain(int channel);
/// @returns The 8-byte definition of instrument @c instrument.
const uint8_t *instrument_definition(int instrument);
};
}
}
#endif /* OPLL_hpp */

View File

@ -12,7 +12,7 @@
#include "../../Components/9918/9918.hpp"
#include "../../Components/SN76489/SN76489.hpp"
#include "../../Components/OPL2/OPL2.hpp"
#include "../../Components/OPL2/OPLL.hpp"
#include "../MachineTypes.hpp"
#include "../../Configurable/Configurable.hpp"

View File

@ -222,6 +222,8 @@
4B595FAE2086DFBA0083CAA8 /* AudioToggle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B595FAC2086DFBA0083CAA8 /* AudioToggle.cpp */; };
4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADB81DE3151600AEC565 /* FileHolder.cpp */; };
4B5FADC01DE3BF2B00AEC565 /* Microdisc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */; };
4B619099245FBF7B0013F202 /* OPLL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B619097245FBF7B0013F202 /* OPLL.cpp */; };
4B61909A245FBF7B0013F202 /* OPLL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B619097245FBF7B0013F202 /* OPLL.cpp */; };
4B622AE5222E0AD5008B59F2 /* DisplayMetrics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B622AE3222E0AD5008B59F2 /* DisplayMetrics.cpp */; };
4B643F3A1D77AD1900D431D6 /* CSStaticAnalyser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F391D77AD1900D431D6 /* CSStaticAnalyser.mm */; };
4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F3E1D77B88000D431D6 /* DocumentController.swift */; };
@ -793,8 +795,6 @@
4BC1317B2346DF2B00E4FF3D /* MSA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC131782346DF2B00E4FF3D /* MSA.cpp */; };
4BC57CD92436A62900FBC404 /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC57CD82436A62900FBC404 /* State.cpp */; };
4BC57CDA2436A62900FBC404 /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC57CD82436A62900FBC404 /* State.cpp */; };
4BC57CE22436BFE000FBC404 /* OPL2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC57CE02436BFE000FBC404 /* OPL2.cpp */; };
4BC57CE32436BFE000FBC404 /* OPL2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC57CE02436BFE000FBC404 /* OPL2.cpp */; };
4BC5C3E022C994CD00795658 /* 68000MoveTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BC5C3DF22C994CC00795658 /* 68000MoveTests.mm */; };
4BC5FC3020CDDDEF00410AA0 /* AppleIIOptions.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BC5FC2E20CDDDEE00410AA0 /* AppleIIOptions.xib */; };
4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC751B11D157E61006C31D9 /* 6522Tests.swift */; };
@ -1152,6 +1152,9 @@
4B619093245CD63E0013F202 /* EnvelopeGenerator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = EnvelopeGenerator.hpp; sourceTree = "<group>"; };
4B619094245E73B90013F202 /* KeyLevelScaler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = KeyLevelScaler.hpp; sourceTree = "<group>"; };
4B619095245FA04B0013F202 /* WaveformGenerator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = WaveformGenerator.hpp; sourceTree = "<group>"; };
4B619096245FBEF80013F202 /* OPLBase.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = OPLBase.hpp; path = Implementation/OPLBase.hpp; sourceTree = "<group>"; };
4B619097245FBF7B0013F202 /* OPLL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = OPLL.cpp; sourceTree = "<group>"; };
4B619098245FBF7B0013F202 /* OPLL.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = OPLL.hpp; sourceTree = "<group>"; };
4B622AE3222E0AD5008B59F2 /* DisplayMetrics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DisplayMetrics.cpp; path = ../../Outputs/DisplayMetrics.cpp; sourceTree = "<group>"; };
4B622AE4222E0AD5008B59F2 /* DisplayMetrics.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DisplayMetrics.hpp; path = ../../Outputs/DisplayMetrics.hpp; sourceTree = "<group>"; };
4B643F381D77AD1900D431D6 /* CSStaticAnalyser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSStaticAnalyser.h; path = StaticAnalyser/CSStaticAnalyser.h; sourceTree = "<group>"; };
@ -3575,6 +3578,9 @@
4BC0CB2F2447EC7C00A79DBB /* Implementation */,
4BC57CE02436BFE000FBC404 /* OPL2.cpp */,
4BC57CE12436BFE000FBC404 /* OPL2.hpp */,
4B619096245FBEF80013F202 /* OPLBase.hpp */,
4B619097245FBF7B0013F202 /* OPLL.cpp */,
4B619098245FBF7B0013F202 /* OPLL.hpp */,
);
path = OPL2;
sourceTree = "<group>";
@ -4375,7 +4381,6 @@
4B894521201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
4B8318B522D3E548006DB630 /* Macintosh.cpp in Sources */,
4B7BA03123C2B19C00B98D9E /* Jasmin.cpp in Sources */,
4BC57CE32436BFE000FBC404 /* OPL2.cpp in Sources */,
4B7F188F2154825E00388727 /* MasterSystem.cpp in Sources */,
4B055AA51FAE85EF0060FFFF /* Encoder.cpp in Sources */,
4BD5D2692199148100DDF17D /* ScanTargetGLSLFragments.cpp in Sources */,
@ -4530,6 +4535,7 @@
4B894537201967B4007DE474 /* Z80.cpp in Sources */,
4B055A9F1FAE85DA0060FFFF /* HFE.cpp in Sources */,
4BD191F52191180E0042E144 /* ScanTarget.cpp in Sources */,
4B61909A245FBF7B0013F202 /* OPLL.cpp in Sources */,
4B055AEC1FAE9BA20060FFFF /* Z80Base.cpp in Sources */,
4B0F94FF208C1A1600FE41D9 /* NIB.cpp in Sources */,
4B0E04EB1FC9E78800F43484 /* CAS.cpp in Sources */,
@ -4651,7 +4657,6 @@
4BEA52631DF339D7007E74F2 /* SoundGenerator.cpp in Sources */,
4BD67DD0209BF27B00AB2146 /* Encoder.cpp in Sources */,
4BAE495920328897004BE78E /* ZX8081OptionsPanel.swift in Sources */,
4BC57CE22436BFE000FBC404 /* OPL2.cpp in Sources */,
4B89451A201967B4007DE474 /* ConfidenceSummary.cpp in Sources */,
4BE0A3EE237BB170002AB46F /* ST.cpp in Sources */,
4B54C0C51F8D91D90050900F /* Keyboard.cpp in Sources */,
@ -4702,6 +4707,7 @@
4BD0FBC3233706A200148981 /* CSApplication.m in Sources */,
4BBC951E1F368D83008F4C34 /* i8272.cpp in Sources */,
4B89449520194CB3007DE474 /* MachineForTarget.cpp in Sources */,
4B619099245FBF7B0013F202 /* OPLL.cpp in Sources */,
4B4A76301DB1A3FA007AAE2E /* AY38910.cpp in Sources */,
4B7BA03423C58B1F00B98D9E /* STX.cpp in Sources */,
4B6A4C991F58F09E00E3F787 /* 6502Base.cpp in Sources */,