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?
65 fn chip_type(&self) -> ChipType {
66 self.chip.chip_type()
67 }
68
69 /// Queue a register write. `reg` encodes the register number in the low
70 /// byte and the port index in bits 8-9. Applied on the next call to
71 /// `generate`.
72 fn write(&mut self, reg: u32, data: u8) {
73 self.queue.push_back((reg, data));
74 }
75
76 fn write_data(&mut self, access: AccessClass, base: u32, data: &[u8]) {
77 let mut state = self.handler_state.borrow_mut();
78 for (index, value) in data.iter().copied().enumerate() {
79 write_byte(&mut state, access, base + index as u32, value);
80 }
81 }
82
83 fn seek_pcm(&mut self, pos: u32) {
84 *self.pcm_offset.borrow_mut() = pos;
85 }
86
87 fn read_pcm(&mut self) -> u8 {
88 let mut offset = self.pcm_offset.borrow_mut();
89 let state = self.handler_state.borrow();
90 let value = read_byte(&state, AccessClass::Pcm, *offset);
91 *offset = offset.saturating_add(1);
92 value
93 }
94
95 /// Advance emulation up to `output_start` and accumulate one stereo
96 /// sample into `buffer[0]` (left) / `buffer[1]` (right), matching
97 /// vgmrender.cpp's `vgm_chip::generate`.
98 fn generate(
99 &mut self,
100 output_start: EmulatedTime,
101 output_step: EmulatedTime,
102 buffer: &mut [i32],
103 ) {
104 let _ = output_step;
105
106 // dequeue at most one pending register write per output sample
107 if let Some((reg, data)) = self.queue.pop_front() {
108 let addr1 = 2 * ((reg >> 8) & 3);
109 let data1 = (reg & 0xff) as u8;
110 let addr2 = addr1
111 + if self.chip_type() == ChipType::Ym2149 {
112 2
113 } else {
114 1
115 };
116 self.chip.pin_mut().write(addr1, data1);
117 self.chip.pin_mut().write(addr2, data);
118 }
119
120 // generate at the chip's native rate, catching up to output_start
121 while self.pos <= output_start {
122 self.chip.pin_mut().generate(&mut self.native);
123 self.pos += self.step;
124 }
125
126 let channels = self.channels;
127 let out = &self.native;
128 match self.chip.chip_type() {
129 ChipType::Ym2203 => {
130 let sum = out[0] + out[1 % channels] + out[2 % channels] + out[3 % channels];
131 buffer[0] += sum;
132 buffer[1] += sum;
133 }
134 ChipType::Ym2608 | ChipType::Ym2610 => {
135 buffer[0] += out[0] + out[2 % channels];
136 buffer[1] += out[1 % channels] + out[2 % channels];
137 }
138 ChipType::Ymf278B => {
139 buffer[0] += out[4 % channels];
140 buffer[1] += out[5 % channels];
141 }
142 _ if channels == 1 => {
143 buffer[0] += out[0];
144 buffer[1] += out[0];
145 }
146 _ => {
147 buffer[0] += out[0];
148 buffer[1] += out[1 % channels];
149 }
150 }
151 }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
39 fn new(chip_type: ChipType, clock: u32) -> Self {
40 let state = Rc::new(RefCell::new(VgmHandlerState {
41 data: std::array::from_fn(|_| Vec::new()),
42 }));
43 let pcm_offset = Rc::new(RefCell::new(0u32));
44 let chip = ffi::create_chip_with_callbacks(
45 chip_type,
46 clock,
47 Box::new(InterfaceCallbacks::new(vgm_handler_with_state(Rc::clone(
48 &state,
49 )))),
50 );
51 let channels = chip.channels() as usize;
52 let step: EmulatedTime = 0x1_0000_0000i64 / i64::from(chip.sample_rate());
53 Self {
54 chip,
55 channels,
56 queue: std::collections::VecDeque::new(),
57 pos: 0,
58 step,
59 native: vec![0i32; channels],
60 handler_state: state,
61 pcm_offset,
62 }
63 }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?
39 fn new(chip_type: ChipType, clock: u32) -> Self {
40 let state = Rc::new(RefCell::new(VgmHandlerState {
41 data: std::array::from_fn(|_| Vec::new()),
42 }));
43 let pcm_offset = Rc::new(RefCell::new(0u32));
44 let chip = ffi::create_chip_with_callbacks(
45 chip_type,
46 clock,
47 Box::new(InterfaceCallbacks::new(vgm_handler_with_state(Rc::clone(
48 &state,
49 )))),
50 );
51 let channels = chip.channels() as usize;
52 let step: EmulatedTime = 0x1_0000_0000i64 / i64::from(chip.sample_rate());
53 Self {
54 chip,
55 channels,
56 queue: std::collections::VecDeque::new(),
57 pos: 0,
58 step,
59 native: vec![0i32; channels],
60 handler_state: state,
61 pcm_offset,
62 }
63 }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 at offset, via the ymfm
write(offset, data) (0/1 = address/data port, 2/3 = extended
address/data port on chips that support it).
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
98 fn generate(
99 &mut self,
100 output_start: EmulatedTime,
101 output_step: EmulatedTime,
102 buffer: &mut [i32],
103 ) {
104 let _ = output_step;
105
106 // dequeue at most one pending register write per output sample
107 if let Some((reg, data)) = self.queue.pop_front() {
108 let addr1 = 2 * ((reg >> 8) & 3);
109 let data1 = (reg & 0xff) as u8;
110 let addr2 = addr1
111 + if self.chip_type() == ChipType::Ym2149 {
112 2
113 } else {
114 1
115 };
116 self.chip.pin_mut().write(addr1, data1);
117 self.chip.pin_mut().write(addr2, data);
118 }
119
120 // generate at the chip's native rate, catching up to output_start
121 while self.pos <= output_start {
122 self.chip.pin_mut().generate(&mut self.native);
123 self.pos += self.step;
124 }
125
126 let channels = self.channels;
127 let out = &self.native;
128 match self.chip.chip_type() {
129 ChipType::Ym2203 => {
130 let sum = out[0] + out[1 % channels] + out[2 % channels] + out[3 % channels];
131 buffer[0] += sum;
132 buffer[1] += sum;
133 }
134 ChipType::Ym2608 | ChipType::Ym2610 => {
135 buffer[0] += out[0] + out[2 % channels];
136 buffer[1] += out[1 % channels] + out[2 % channels];
137 }
138 ChipType::Ymf278B => {
139 buffer[0] += out[4 % channels];
140 buffer[1] += out[5 % channels];
141 }
142 _ if channels == 1 => {
143 buffer[0] += out[0];
144 buffer[1] += out[0];
145 }
146 _ => {
147 buffer[0] += out[0];
148 buffer[1] += out[1 % channels];
149 }
150 }
151 }Sourcepub fn read(self: Pin<&mut Self>, offset: u32) -> u8
pub fn read(self: Pin<&mut Self>, offset: u32) -> u8
Read from offset, via the ymfm read(offset) 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 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
98 fn generate(
99 &mut self,
100 output_start: EmulatedTime,
101 output_step: EmulatedTime,
102 buffer: &mut [i32],
103 ) {
104 let _ = output_step;
105
106 // dequeue at most one pending register write per output sample
107 if let Some((reg, data)) = self.queue.pop_front() {
108 let addr1 = 2 * ((reg >> 8) & 3);
109 let data1 = (reg & 0xff) as u8;
110 let addr2 = addr1
111 + if self.chip_type() == ChipType::Ym2149 {
112 2
113 } else {
114 1
115 };
116 self.chip.pin_mut().write(addr1, data1);
117 self.chip.pin_mut().write(addr2, data);
118 }
119
120 // generate at the chip's native rate, catching up to output_start
121 while self.pos <= output_start {
122 self.chip.pin_mut().generate(&mut self.native);
123 self.pos += self.step;
124 }
125
126 let channels = self.channels;
127 let out = &self.native;
128 match self.chip.chip_type() {
129 ChipType::Ym2203 => {
130 let sum = out[0] + out[1 % channels] + out[2 % channels] + out[3 % channels];
131 buffer[0] += sum;
132 buffer[1] += sum;
133 }
134 ChipType::Ym2608 | ChipType::Ym2610 => {
135 buffer[0] += out[0] + out[2 % channels];
136 buffer[1] += out[1 % channels] + out[2 % channels];
137 }
138 ChipType::Ymf278B => {
139 buffer[0] += out[4 % channels];
140 buffer[1] += out[5 % channels];
141 }
142 _ if channels == 1 => {
143 buffer[0] += out[0];
144 buffer[1] += out[0];
145 }
146 _ => {
147 buffer[0] += out[0];
148 buffer[1] += out[1 % channels];
149 }
150 }
151 }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}