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 or chip port at `offset`, via the upstream
140 /// `write(offset, data)` API. The common mapping is 0/1 for the
141 /// address/data ports. OPN/OPNA chips generally use 2/3 for their
142 /// extended address/data ports; YMF262/YMF289B use 2 for the upper
143 /// address and 3 for regular data; YMF278B uses 4/5 for PCM
144 /// address/data. YM2149 uses 2 for write data. Unsupported offsets
145 /// follow the selected chip's upstream behavior.
146 fn write(self: Pin<&mut Chip>, offset: u32, data: u8);
147
148 /// Read from a chip port at `offset`, via the upstream `read(offset)`
149 /// API. The common mapping is 0 for status and 1 for data; extended
150 /// status/data and chip-specific ports use the offsets defined by the
151 /// selected upstream chip. YM2149 reads its data port at offset 3.
152 fn read(self: Pin<&mut Chip>, offset: u32) -> u8;
153
154 /// Generate `buffer.len() / channels()` samples at the chip's native
155 /// sample rate, overwriting `buffer` (channel-interleaved); wraps
156 /// the ymfm `generate(output_data*, numsamples)` API. This generates
157 /// one native sample at a time. For each sample, it also advances the
158 /// internal clock counter used by
159 /// timers, including those required by modes such as CSM, and by
160 /// BUSY state tracking.
161 fn generate(self: Pin<&mut Chip>, buffer: &mut [i32]);
162
163 /// Serialize the full internal chip state via the ymfm
164 /// `save_restore(ymfm_saved_state&)` with `saving = true`).
165 fn save_state(self: Pin<&mut Chip>) -> Vec<u8>;
166
167 /// Restore state previously produced by `save_state` (via the ymfm
168 /// `save_restore(ymfm_saved_state&)` with `saving = false`). The
169 /// chip must be of the same type and clock as when the state was
170 /// saved; ymfm does not version or validate the saved data itself.
171 fn restore_state(self: Pin<&mut Chip>, data: &[u8]);
172 }
173}