Public Member Functions | Static Public Attributes | Protected Member Functions | List of all members
openmsx::YM2413Core Class Referenceabstract

Abstract interface for the YM2413 core. More...

#include <YM2413Core.hh>

Inheritance diagram for openmsx::YM2413Core:
Inheritance graph

Public Member Functions

virtual ~YM2413Core ()=default
virtual void reset ()=0
 Reset this YM2413 core. More...
virtual void writeReg (byte reg, byte value)=0
 Write to a YM2413 register. More...
virtual byte peekReg (byte reg) const =0
 Read from a YM2413 register. More...
virtual void generateChannels (float *bufs[11], unsigned num)=0
 Generate the sound output. More...
virtual float getAmplificationFactor () const =0
 Returns normalization factor. More...

Static Public Attributes

static constexpr int CLOCK_FREQ = 3579545
 Input clock frequency. More...

Protected Member Functions

 YM2413Core ()=default

Detailed Description

Abstract interface for the YM2413 core.

We currently have two concrete implementations:

This interface separates the actual YM2413 emulation from the rest of the (sound) emulation details. This allows to more easily share this implementation between different emulators. It also allows to more easily test the YM2413 emulation in isolation.

There are two main functions in this interface: write to registers and get output samples. All timing information is implicit in the order of the calls to these functions (e.g. write some register, generate 10 output samples, write another register, ...).

Definition at line 26 of file YM2413Core.hh.

Constructor & Destructor Documentation

◆ ~YM2413Core()

virtual openmsx::YM2413Core::~YM2413Core ( )

◆ YM2413Core()

openmsx::YM2413Core::YM2413Core ( )

Member Function Documentation

◆ generateChannels()

virtual void openmsx::YM2413Core::generateChannels ( float *  bufs[11],
unsigned  num 
pure virtual

Generate the sound output.

bufsPointers to output buffers.
numThe number of required output samples.

The requested number of samples must be strictly bigger than zero.

The output of the different channels is put in separate output buffers. This makes it possible to e.g. record individual channels or to pan, mute or adjust volume per channel. The YM2413 can operate in two modes: 9 channels or 6 channels + 5 drum channels. The latter mode requires a total of 11 output buffers. In the first mode, the last two output buffers are filled with silence (this is very efficient, see below). Each output buffer should be big enough to hold at least 'num' number of ints.

The output is not simply stored in the buffer, but added to the existing data in the buffer. So you'll have to zero the content of the buffer before passing it to this function. OTOH if you want to combine (some of) the channels, you can pass the same buffer for all those channels. This approach may have a little overhead when you're interested in all channels, but it is very efficient if you're only interested in the combined channels (the most common case). You can even directly combine this output with other chips with the same native frequency (like Y8950 or YMF262).

When the core detects that some channel is silent, it will assign nullptr to the buffer pointer (so the content of the buffer is left unchanged, but the pointer to that buffer is set to zero). When all the channels you're interested in are silent you can even skip all subsequent audio processing for this channel (e.g. skip resampling to 44kHz). It is very common that some or even all of the channels are silent, so it's definitely worth it to implement this optimization. Also the cores internally try to detect silent channels very early, so an idle YM2413 core generally requires very little emulation time.

◆ getAmplificationFactor()

virtual float openmsx::YM2413Core::getAmplificationFactor ( ) const
pure virtual

Returns normalization factor.

The output of the generateChannels() method should still be amplified (=multiplied) with this factor to get a consistent volume level across the different implementations of the YM2413 core. This allows to internally calculate with native volume levels, and possibly results in slightly simpler and/or faster code. It's very likely that subsequent audio processing steps (like resampler, filters or volume adjustments) must anyway still multiply the output sample values, so this factor can be folded-in for free.

◆ peekReg()

virtual byte openmsx::YM2413Core::peekReg ( byte  reg) const
pure virtual

Read from a YM2413 register.

Note that the real YM2413 chip doesn't allow to read the registers. This returns the last written value or the default value if this register hasn't been written to since the last reset() call. Reading registers has no influence on the generated sound.

◆ reset()

virtual void openmsx::YM2413Core::reset ( )
pure virtual

Reset this YM2413 core.

◆ writeReg()

virtual void openmsx::YM2413Core::writeReg ( byte  reg,
byte  value 
pure virtual

Write to a YM2413 register.

Member Data Documentation


constexpr int openmsx::YM2413Core::CLOCK_FREQ = 3579545

Input clock frequency.

An output sample is generated every 72 cycles. So the output sample frequency is effectively 49716Hz. If you need the output at e.g. 44100Hz you need to resample the data. Generating the output at the native YM2413 frequency allows for quite some simplifications in the implementation of the cores. It also generally results in better sound quality. At least if the resampler step itself doesn't degrade the quality again (Certainly don't simply skip some of the samples to get to 44kHz, at the very least do linear interpolation. But preferably use a better resample algorithm).

Definition at line 40 of file YM2413Core.hh.

The documentation for this class was generated from the following file: