Skip to content

opal-rust v3.0.0-1

Latest

Choose a tag to compare

@github-actions github-actions released this 24 Oct 23:25

Changed

  • 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.