You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Binds opal 3.0.0. The emulation core is new. The eight C functions keep
their names and C signatures. Rendered output is not bit-identical to 2.0.2.
Opal is now a wrapper around the raw mirror, which moved to opal::ffi::Opal. It derefs to it, so reads such as chip.op[3].eg_out
compile unchanged. Field writes and struct literals no longer compile. The C
core trusts fields such as algorithm, multiple, f_number, queue_head, and sample_rate, so a bad value written from safe code was
undefined behavior, in 2.0.2-2 as well. The unsafe methods Opal::raw_mut and Opal::from_raw give write access. Their safety
sections list the fields that must stay in range. The opal::ffi
functions now take *mut ffi::Opal instead of *mut Opal, so a call that
passed &raw mut chip passes chip.raw_mut() instead.
Struct mirrors follow the new layout. The visualizer fields keep their names
and meaning. Those are envelope_stage, eg_out, key, mod_source, and out on Operator, and op_slot, pair_index, out_source, chan_type, left_pan, and right_pan on Channel. The core no longer reads mod_source, out_source, or chan_type, so writing them no longer
changes the sound. Other fields may be renamed, retyped, or rescaled.
WriteBuf is now QueuedWrite, with fields due, reg_num, and value. output_enable replaces the old per-speaker flags. Opal::opl3_enabled is
now new_mode. sample_counter replaces chip_timer. tremolo_depth and vibrato_depth hold the BDh bits that tremolo_shift and vib_shift
encoded as shifts. hi_hat_phase and cymbal_phase hold the phases that
the rm_* bits sampled. The write-buffer cursors are queue, queue_head, queue_count, chip_samples, and last_due. Fields that used to be bool
are u8, matching uint8_t in the header.
Operator and channel register fields hold raw register values. sustain_level keeps its name but is now a u8 from 0 to 15 instead of a
scaled u16 level. Reads that don't name its type still compile and get
different numbers. total_level, multiple, feedback, f_number, and block replace output_level, freq_mult_times2, feedback_shift, freq, and octave. algorithm replaces alg and uses a new encoding.
The envelope rates and waveform are u8 too.
NEW (register 105h bit 0) still gates new writes. While it is clear, bank 1
writes other than 105h land in bank 0, E0h writes keep only waveforms 0-3,
and a C0h write turns on both speakers. Changing NEW no longer rewrites
stored state or how it plays, so a waveform 4-7 written while NEW was set
keeps playing after NEW is cleared. All 18 channels keep playing, and
four-operator pairs follow register 104h alone.
A masked timer sets nothing. Setting a timer's mask bit clears a flag that
is already set. IRQ stays set only while a flag is set.
Opal::new and set_sample_rate treat a rate of 0 as 49716 Hz. Anything
above i32::MAX - 49716 clamps to that limit. A u32 that does not fit in
a C int is passed as c_int::MAX, which the core then clamps. set_sample_rate no longer clears the write queue or the output history, so
a queued write survives it. It still resets the resampler phase in sample_accum. pan clamps a level above 127.
Opal::new still leaves every operator in release with eg_out at 0x1FF.
It now enables both speakers on every channel, so a voice is audible without
a C0 write. The instance is about 66 KiB.
Added
Tests for the 3.0.0 behavior. NEW leaves stored state alone. Bank 1 writes
reach bank 1, and waveforms 4-7 are stored, only while NEW is set.
Four-operator pairing stays after NEW is cleared. Masked timers set nothing. Sample-rate clamping, the
write queue surviving set_sample_rate, and pan clamping are covered too.
So is a raw copy wrapped back with from_raw, and a compile_fail doctest
checks that safe code cannot write chip state.
Notes on the update are in doc/3.0.0.md.
Removed
Operator::slot_index, Operator::chan_index, and Channel::chan_index. op_slot, modulator_slot, and carrier_slot map channels to operators.
Internal state that upstream dropped, including phase_out, phase_reset, eg_ksl, fb_mod, cha, chb, chc, chd, vib_pos, the eg_*
envelope timer fields, and rhythm_reg.