Skip to main content

Chip

Struct Chip 

Source
pub struct Chip { /* private fields */ }
Expand description

Opaque handle to a single emulated chip instance.

Implementations§

Source§

impl Chip

Source

pub fn chip_type(&self) -> ChipType

Which chip this instance represents.

Examples found in repository?
examples/vgmrender.rs (line 69)
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    }
Source

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?
examples/buildall.rs (line 15)
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
Hide additional examples
examples/vgmrender.rs (line 54)
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    }
Source

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?
examples/vgmrender.rs (line 55)
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    }
Source

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?
examples/buildall.rs (line 6)
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}
Source

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.

Source

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.

Source

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?
examples/buildall.rs (line 13)
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
Hide additional examples
examples/vgmrender.rs (line 119)
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    }
Source

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?
examples/buildall.rs (line 12)
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}
Source

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?
examples/buildall.rs (line 17)
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
Hide additional examples
examples/vgmrender.rs (line 125)
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    }
Source

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?
examples/buildall.rs (line 8)
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}
Source

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?
examples/buildall.rs (line 10)
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}

Trait Implementations§

Source§

impl ExternType for Chip

Source§

type Kind = Opaque

Source§

type Id

A type-level representation of the type’s C++ namespace and type name. Read more
Source§

impl UniquePtrTarget for Chip

Auto Trait Implementations§

§

impl !Freeze for Chip

§

impl !Send for Chip

§

impl !Sync for Chip

§

impl !Unpin for Chip

§

impl RefUnwindSafe for Chip

§

impl UnsafeUnpin for Chip

§

impl UnwindSafe for Chip

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.