pub struct Chip { /* private fields */ }Expand description
Opaque handle to a single emulated chip instance.
Implementations§
Source§impl Chip
impl Chip
Sourcepub fn chip_type(&self) -> ChipType
pub fn chip_type(&self) -> ChipType
Which chip this instance represents.
Examples found in repository?
68 fn chip_type(&self) -> ChipType {
69 self.chip.chip_type()
70 }
71
72 /// Queue a register write. `reg` encodes the register number in the low
73 /// byte and the port index in bits 8-9. Applied on the next call to
74 /// `generate`.
75 fn write(&mut self, reg: u32, data: u8) {
76 self.queue.push_back((reg, data));
77 }
78
79 fn write_data(&mut self, access: AccessClass, base: u32, data: &[u8]) {
80 let mut state = self.handler_state.borrow_mut();
81 for (index, value) in data.iter().copied().enumerate() {
82 write_byte(&mut state, access, base + index as u32, value);
83 }
84 }
85
86 fn seek_pcm(&mut self, pos: u32) {
87 *self.pcm_offset.borrow_mut() = pos;
88 }
89
90 fn read_pcm(&mut self) -> u8 {
91 let mut offset = self.pcm_offset.borrow_mut();
92 let state = self.handler_state.borrow();
93 let value = read_byte(&state, AccessClass::Pcm, *offset);
94 *offset = offset.saturating_add(1);
95 value
96 }
97
98 /// Advance emulation up to `output_start` and accumulate one stereo
99 /// sample into `buffer[0]` (left) / `buffer[1]` (right), matching
100 /// vgmrender.cpp's `vgm_chip::generate`.
101 fn generate(
102 &mut self,
103 output_start: EmulatedTime,
104 output_step: EmulatedTime,
105 buffer: &mut [i32],
106 ) {
107 let _ = output_step;
108
109 // dequeue at most one pending register write per output sample
110 if let Some((reg, data)) = self.queue.pop_front() {
111 let addr1 = 2 * ((reg >> 8) & 3);
112 let data1 = (reg & 0xff) as u8;
113 let addr2 = addr1
114 + if self.chip_type() == ChipType::Ym2149 {
115 2
116 } else {
117 1
118 };
119 self.chip.pin_mut().write(addr1, data1);
120 self.chip.pin_mut().write(addr2, data);
121 }
122
123 // generate at the chip's native rate, catching up to output_start
124 while self.pos <= output_start {
125 self.chip.pin_mut().generate(&mut self.native);
126 self.pos += self.step;
127 }
128
129 let channels = self.channels;
130 let out = &self.native;
131 match self.chip.chip_type() {
132 ChipType::Ym2203 => {
133 let sum = out[0] + out[1 % channels] + out[2 % channels] + out[3 % channels];
134 buffer[0] += sum;
135 buffer[1] += sum;
136 }
137 ChipType::Ym2608 | ChipType::Ym2610 => {
138 buffer[0] += out[0] + out[2 % channels];
139 buffer[1] += out[1 % channels] + out[2 % channels];
140 }
141 ChipType::Ymf278B => {
142 buffer[0] += out[4 % channels];
143 buffer[1] += out[5 % channels];
144 }
145 _ if channels == 1 => {
146 buffer[0] += out[0];
147 buffer[1] += out[0];
148 }
149 _ => {
150 buffer[0] += out[0];
151 buffer[1] += out[1 % channels];
152 }
153 }
154 }Sourcepub fn channels(&self) -> u32
pub fn channels(&self) -> u32
Number of output channels this chip produces per generated sample
(via the concrete ymfm chip class’s OUTPUTS constant).
Examples found in repository?
3fn exercise_chip(chip_type: ChipType) {
4 let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6 chip.pin_mut().reset();
7
8 let saved = chip.pin_mut().save_state();
9 assert!(!saved.is_empty());
10 chip.pin_mut().restore_state(&saved);
11
12 chip.pin_mut().read(0);
13 chip.pin_mut().write(0, 0);
14
15 let channels = chip.channels() as usize;
16 let mut samples = vec![0_i32; channels * 20];
17 chip.pin_mut().generate(&mut samples);
18}More examples
42 fn new(chip_type: ChipType, clock: u32) -> Self {
43 let state = Rc::new(RefCell::new(VgmHandlerState {
44 data: std::array::from_fn(|_| Vec::new()),
45 }));
46 let pcm_offset = Rc::new(RefCell::new(0u32));
47 let chip = ffi::create_chip_with_callbacks(
48 chip_type,
49 clock,
50 Box::new(InterfaceCallbacks::new(vgm_handler_with_state(Rc::clone(
51 &state,
52 )))),
53 );
54 let channels = chip.channels() as usize;
55 let step: EmulatedTime = 0x1_0000_0000i64 / i64::from(chip.sample_rate());
56 Self {
57 chip,
58 channels,
59 queue: std::collections::VecDeque::new(),
60 pos: 0,
61 step,
62 native: vec![0i32; channels],
63 handler_state: state,
64 pcm_offset,
65 }
66 }Sourcepub fn sample_rate(&self) -> u32
pub fn sample_rate(&self) -> u32
Native output sample rate for the clock this chip was created
with (via the ymfm sample_rate(uint32_t input_clock) API).
Examples found in repository?
42 fn new(chip_type: ChipType, clock: u32) -> Self {
43 let state = Rc::new(RefCell::new(VgmHandlerState {
44 data: std::array::from_fn(|_| Vec::new()),
45 }));
46 let pcm_offset = Rc::new(RefCell::new(0u32));
47 let chip = ffi::create_chip_with_callbacks(
48 chip_type,
49 clock,
50 Box::new(InterfaceCallbacks::new(vgm_handler_with_state(Rc::clone(
51 &state,
52 )))),
53 );
54 let channels = chip.channels() as usize;
55 let step: EmulatedTime = 0x1_0000_0000i64 / i64::from(chip.sample_rate());
56 Self {
57 chip,
58 channels,
59 queue: std::collections::VecDeque::new(),
60 pos: 0,
61 step,
62 native: vec![0i32; channels],
63 handler_state: state,
64 pcm_offset,
65 }
66 }Sourcepub fn reset(self: Pin<&mut Self>)
pub fn reset(self: Pin<&mut Self>)
Reset the chip to its post-power-on state (via the ymfm reset() API).
Examples found in repository?
3fn exercise_chip(chip_type: ChipType) {
4 let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6 chip.pin_mut().reset();
7
8 let saved = chip.pin_mut().save_state();
9 assert!(!saved.is_empty());
10 chip.pin_mut().restore_state(&saved);
11
12 chip.pin_mut().read(0);
13 chip.pin_mut().write(0, 0);
14
15 let channels = chip.channels() as usize;
16 let mut samples = vec![0_i32; channels * 20];
17 chip.pin_mut().generate(&mut samples);
18}Sourcepub fn set_fidelity(self: Pin<&mut Self>, fidelity: Fidelity)
pub fn set_fidelity(self: Pin<&mut Self>, fidelity: Fidelity)
Select the sample-rate/accuracy tradeoff (via the ymfm
set_fidelity(opn_fidelity)). Only meaningful for
YM2203/YM2608/YM2610/YM2610B; a no-op on other chips.
Sourcepub fn set_instrument_data(self: Pin<&mut Self>, data: &[u8]) -> bool
pub fn set_instrument_data(self: Pin<&mut Self>, data: &[u8]) -> bool
Replace the 0x90-byte instrument data on OPLL-family chips. Returns false for unsupported chip types or an incorrectly sized data buffer.
Sourcepub fn write(self: Pin<&mut Self>, offset: u32, data: u8)
pub fn write(self: Pin<&mut Self>, offset: u32, data: u8)
Write to a register or chip port at offset, via the upstream
write(offset, data) API. The common mapping is 0/1 for the
address/data ports. OPN/OPNA chips generally use 2/3 for their
extended address/data ports; YMF262/YMF289B use 2 for the upper
address and 3 for regular data; YMF278B uses 4/5 for PCM
address/data. YM2149 uses 2 for write data. Unsupported offsets
follow the selected chip’s upstream behavior.
Examples found in repository?
3fn exercise_chip(chip_type: ChipType) {
4 let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6 chip.pin_mut().reset();
7
8 let saved = chip.pin_mut().save_state();
9 assert!(!saved.is_empty());
10 chip.pin_mut().restore_state(&saved);
11
12 chip.pin_mut().read(0);
13 chip.pin_mut().write(0, 0);
14
15 let channels = chip.channels() as usize;
16 let mut samples = vec![0_i32; channels * 20];
17 chip.pin_mut().generate(&mut samples);
18}More examples
101 fn generate(
102 &mut self,
103 output_start: EmulatedTime,
104 output_step: EmulatedTime,
105 buffer: &mut [i32],
106 ) {
107 let _ = output_step;
108
109 // dequeue at most one pending register write per output sample
110 if let Some((reg, data)) = self.queue.pop_front() {
111 let addr1 = 2 * ((reg >> 8) & 3);
112 let data1 = (reg & 0xff) as u8;
113 let addr2 = addr1
114 + if self.chip_type() == ChipType::Ym2149 {
115 2
116 } else {
117 1
118 };
119 self.chip.pin_mut().write(addr1, data1);
120 self.chip.pin_mut().write(addr2, data);
121 }
122
123 // generate at the chip's native rate, catching up to output_start
124 while self.pos <= output_start {
125 self.chip.pin_mut().generate(&mut self.native);
126 self.pos += self.step;
127 }
128
129 let channels = self.channels;
130 let out = &self.native;
131 match self.chip.chip_type() {
132 ChipType::Ym2203 => {
133 let sum = out[0] + out[1 % channels] + out[2 % channels] + out[3 % channels];
134 buffer[0] += sum;
135 buffer[1] += sum;
136 }
137 ChipType::Ym2608 | ChipType::Ym2610 => {
138 buffer[0] += out[0] + out[2 % channels];
139 buffer[1] += out[1 % channels] + out[2 % channels];
140 }
141 ChipType::Ymf278B => {
142 buffer[0] += out[4 % channels];
143 buffer[1] += out[5 % channels];
144 }
145 _ if channels == 1 => {
146 buffer[0] += out[0];
147 buffer[1] += out[0];
148 }
149 _ => {
150 buffer[0] += out[0];
151 buffer[1] += out[1 % channels];
152 }
153 }
154 }Sourcepub fn read(self: Pin<&mut Self>, offset: u32) -> u8
pub fn read(self: Pin<&mut Self>, offset: u32) -> u8
Read from a chip port at offset, via the upstream read(offset)
API. The common mapping is 0 for status and 1 for data; extended
status/data and chip-specific ports use the offsets defined by the
selected upstream chip. YM2149 reads its data port at offset 3.
Examples found in repository?
3fn exercise_chip(chip_type: ChipType) {
4 let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6 chip.pin_mut().reset();
7
8 let saved = chip.pin_mut().save_state();
9 assert!(!saved.is_empty());
10 chip.pin_mut().restore_state(&saved);
11
12 chip.pin_mut().read(0);
13 chip.pin_mut().write(0, 0);
14
15 let channels = chip.channels() as usize;
16 let mut samples = vec![0_i32; channels * 20];
17 chip.pin_mut().generate(&mut samples);
18}Sourcepub fn generate(self: Pin<&mut Self>, buffer: &mut [i32])
pub fn generate(self: Pin<&mut Self>, buffer: &mut [i32])
Generate buffer.len() / channels() samples at the chip’s native
sample rate, overwriting buffer (channel-interleaved); wraps
the ymfm generate(output_data*, numsamples) API. This generates
one native sample at a time. For each sample, it also advances the
internal clock counter used by
timers, including those required by modes such as CSM, and by
BUSY state tracking.
Examples found in repository?
3fn exercise_chip(chip_type: ChipType) {
4 let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6 chip.pin_mut().reset();
7
8 let saved = chip.pin_mut().save_state();
9 assert!(!saved.is_empty());
10 chip.pin_mut().restore_state(&saved);
11
12 chip.pin_mut().read(0);
13 chip.pin_mut().write(0, 0);
14
15 let channels = chip.channels() as usize;
16 let mut samples = vec![0_i32; channels * 20];
17 chip.pin_mut().generate(&mut samples);
18}More examples
101 fn generate(
102 &mut self,
103 output_start: EmulatedTime,
104 output_step: EmulatedTime,
105 buffer: &mut [i32],
106 ) {
107 let _ = output_step;
108
109 // dequeue at most one pending register write per output sample
110 if let Some((reg, data)) = self.queue.pop_front() {
111 let addr1 = 2 * ((reg >> 8) & 3);
112 let data1 = (reg & 0xff) as u8;
113 let addr2 = addr1
114 + if self.chip_type() == ChipType::Ym2149 {
115 2
116 } else {
117 1
118 };
119 self.chip.pin_mut().write(addr1, data1);
120 self.chip.pin_mut().write(addr2, data);
121 }
122
123 // generate at the chip's native rate, catching up to output_start
124 while self.pos <= output_start {
125 self.chip.pin_mut().generate(&mut self.native);
126 self.pos += self.step;
127 }
128
129 let channels = self.channels;
130 let out = &self.native;
131 match self.chip.chip_type() {
132 ChipType::Ym2203 => {
133 let sum = out[0] + out[1 % channels] + out[2 % channels] + out[3 % channels];
134 buffer[0] += sum;
135 buffer[1] += sum;
136 }
137 ChipType::Ym2608 | ChipType::Ym2610 => {
138 buffer[0] += out[0] + out[2 % channels];
139 buffer[1] += out[1 % channels] + out[2 % channels];
140 }
141 ChipType::Ymf278B => {
142 buffer[0] += out[4 % channels];
143 buffer[1] += out[5 % channels];
144 }
145 _ if channels == 1 => {
146 buffer[0] += out[0];
147 buffer[1] += out[0];
148 }
149 _ => {
150 buffer[0] += out[0];
151 buffer[1] += out[1 % channels];
152 }
153 }
154 }Sourcepub fn save_state(self: Pin<&mut Self>) -> Vec<u8> ⓘ
pub fn save_state(self: Pin<&mut Self>) -> Vec<u8> ⓘ
Serialize the full internal chip state via the ymfm
save_restore(ymfm_saved_state&) with saving = true).
Examples found in repository?
3fn exercise_chip(chip_type: ChipType) {
4 let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6 chip.pin_mut().reset();
7
8 let saved = chip.pin_mut().save_state();
9 assert!(!saved.is_empty());
10 chip.pin_mut().restore_state(&saved);
11
12 chip.pin_mut().read(0);
13 chip.pin_mut().write(0, 0);
14
15 let channels = chip.channels() as usize;
16 let mut samples = vec![0_i32; channels * 20];
17 chip.pin_mut().generate(&mut samples);
18}Sourcepub fn restore_state(self: Pin<&mut Self>, data: &[u8])
pub fn restore_state(self: Pin<&mut Self>, data: &[u8])
Restore state previously produced by save_state (via the ymfm
save_restore(ymfm_saved_state&) with saving = false). The
chip must be of the same type and clock as when the state was
saved; ymfm does not version or validate the saved data itself.
Examples found in repository?
3fn exercise_chip(chip_type: ChipType) {
4 let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6 chip.pin_mut().reset();
7
8 let saved = chip.pin_mut().save_state();
9 assert!(!saved.is_empty());
10 chip.pin_mut().restore_state(&saved);
11
12 chip.pin_mut().read(0);
13 chip.pin_mut().write(0, 0);
14
15 let channels = chip.channels() as usize;
16 let mut samples = vec![0_i32; channels * 20];
17 chip.pin_mut().generate(&mut samples);
18}