ymfm_sys/lib.rs
1#![doc = include_str!("../README.md")]
2
3use cxx::UniquePtr;
4
5mod callback;
6
7pub use callback::{InterfaceCallbacks, InterfaceHandler};
8pub(crate) use callback::{
9 advance_clock, default_callbacks, read_data, write_data, ymfm_external_read,
10 ymfm_external_write, ymfm_is_busy, ymfm_set_busy_end, ymfm_set_timer, ymfm_update_irq,
11};
12
13/// Convenience alias for the common case of holding a chip instance.
14pub type ChipPtr = UniquePtr<ffi::Chip>;
15
16#[cxx::bridge(namespace = "ymfm_sys")]
17pub mod ffi {
18 extern "Rust" {
19 type InterfaceCallbacks;
20
21 fn default_callbacks() -> Box<InterfaceCallbacks>;
22
23 fn advance_clock(callbacks: &InterfaceCallbacks, clocks: i64) -> u8;
24 fn read_data(
25 callbacks: &InterfaceCallbacks,
26 access: AccessClass,
27 base: u32,
28 length: u32,
29 ) -> Vec<u8>;
30 fn write_data(callbacks: &InterfaceCallbacks, access: AccessClass, base: u32, data: &[u8]);
31 fn ymfm_external_read(
32 callbacks: &InterfaceCallbacks,
33 access: AccessClass,
34 offset: u32,
35 ) -> u8;
36 fn ymfm_external_write(
37 callbacks: &InterfaceCallbacks,
38 access: AccessClass,
39 offset: u32,
40 data: u8,
41 );
42 fn ymfm_is_busy(callbacks: &InterfaceCallbacks) -> bool;
43 fn ymfm_set_busy_end(callbacks: &InterfaceCallbacks, clocks: u32);
44 fn ymfm_set_timer(callbacks: &InterfaceCallbacks, tnum: u32, duration_in_clocks: i32);
45 fn ymfm_update_irq(callbacks: &InterfaceCallbacks, asserted: bool);
46 }
47
48 /// Supported Yamaha FM/SSG chip families.
49 ///
50 /// `Ym2610B` exists only to select the YM2610B variant at creation time;
51 /// `Chip::chip_type` normalizes it back to `Ym2610`, matching how ymfm
52 /// itself treats the two revisions identically for register routing.
53 #[repr(u32)]
54 enum ChipType {
55 Ym2149,
56 Ym2151,
57 Ym2164,
58 Ym2203,
59 Ym2413,
60 Ym2423,
61 Ym2608,
62 Ym2610,
63 Ym2610B,
64 Ym2612,
65 Ym3438,
66 Ymf276,
67 Ym3526,
68 Ym3533,
69 Y8950,
70 Ym3812,
71 Ymf262,
72 Ymf281,
73 Ymf289B,
74 Ymf278B,
75 Ymf288,
76 Ym3806,
77 Ds1001,
78 Ym2414,
79 }
80
81 /// External data classes a chip may read ROM/RAM data from.
82 #[repr(u32)]
83 enum AccessClass {
84 Io,
85 AdpcmA,
86 AdpcmB,
87 Pcm,
88 }
89
90 /// Sample-rate/accuracy tradeoff, via the ymfm `opn_fidelity` setting.
91 /// Only meaningful for YM2203/YM2608/YM2610/YM2610B; a no-op elsewhere.
92 #[repr(u32)]
93 enum Fidelity {
94 Max,
95 Min,
96 Med,
97 }
98
99 unsafe extern "C++" {
100 include!("ymfm-sys/src/shim.h");
101
102 /// Opaque handle to a single emulated chip instance.
103 type Chip;
104
105 /// Create a chip with all optional interface callbacks disabled.
106 fn create_chip(chip_type: ChipType, clock: u32) -> UniquePtr<Chip>;
107
108 /// Create a chip and forward ymfm interface callbacks to `callbacks`.
109 fn create_chip_with_callbacks(
110 chip_type: ChipType,
111 clock: u32,
112 callbacks: Box<InterfaceCallbacks>,
113 ) -> UniquePtr<Chip>;
114
115 /// Which chip this instance represents.
116 fn chip_type(self: &Chip) -> ChipType;
117
118 /// Number of output channels this chip produces per generated sample
119 /// (via the concrete ymfm chip class's `OUTPUTS` constant).
120 fn channels(self: &Chip) -> u32;
121
122 /// Native output sample rate for the clock this chip was created
123 /// with (via the ymfm `sample_rate(uint32_t input_clock)` API).
124 fn sample_rate(self: &Chip) -> u32;
125
126 /// Reset the chip to its post-power-on state (via the ymfm `reset()` API).
127 fn reset(self: Pin<&mut Chip>);
128
129 /// Select the sample-rate/accuracy tradeoff (via the ymfm
130 /// `set_fidelity(opn_fidelity)`). Only meaningful for
131 /// YM2203/YM2608/YM2610/YM2610B; a no-op on other chips.
132 fn set_fidelity(self: Pin<&mut Chip>, fidelity: Fidelity);
133
134 /// Replace the 0x90-byte instrument data on OPLL-family chips.
135 /// Returns false for unsupported chip types or an incorrectly sized
136 /// data buffer.
137 fn set_instrument_data(self: Pin<&mut Chip>, data: &[u8]) -> bool;
138
139 /// Write to a register at `offset`, via the ymfm
140 /// `write(offset, data)` (0/1 = address/data port, 2/3 = extended
141 /// address/data port on chips that support it).
142 fn write(self: Pin<&mut Chip>, offset: u32, data: u8);
143
144 /// Read from `offset`, via the ymfm `read(offset)` API.
145 fn read(self: Pin<&mut Chip>, offset: u32) -> u8;
146
147 /// Generate `buffer.len() / channels()` samples at the chip's native
148 /// sample rate, overwriting `buffer` (channel-interleaved); wraps
149 /// the ymfm `generate(output_data*, numsamples)` API. This generates
150 /// one native sample at a time. For each sample, it also advances the
151 /// internal clock counter used by
152 /// timers, including those required by modes such as CSM, and by
153 /// BUSY state tracking.
154 fn generate(self: Pin<&mut Chip>, buffer: &mut [i32]);
155
156 /// Serialize the full internal chip state via the ymfm
157 /// `save_restore(ymfm_saved_state&)` with `saving = true`).
158 fn save_state(self: Pin<&mut Chip>) -> Vec<u8>;
159
160 /// Restore state previously produced by `save_state` (via the ymfm
161 /// `save_restore(ymfm_saved_state&)` with `saving = false`). The
162 /// chip must be of the same type and clock as when the state was
163 /// saved; ymfm does not version or validate the saved data itself.
164 fn restore_state(self: Pin<&mut Chip>, data: &[u8]);
165 }
166}