Skip to main content

ym2149_core/
chip.rs

1// Imports
2use crate::audio::{AudioChannel, AudioChannelData, Note};
3use crate::command::{Command, CommandOutput};
4use crate::envelopes::{Envelope, EnvelopeFrequency};
5use crate::errors::Error;
6use crate::io::{IoPort, IoPortMixerSettings};
7use crate::register::{LEVEL_REGS, Register, ValidRegister};
8
9// =========================================================
10// ====================== CHIP STRUCT ======================
11// =========================================================
12
13/// A YM2149 chip struct.
14///
15/// The master_clock_frequency value is used to convert a frequency into a tone period by .tone_hz()
16///
17/// Example code:
18/// ```no_run
19/// use ym2149_core::{
20///     command::{Command, CommandOutput},
21///     io::IoPortMixerSettings,
22///     chip::YM2149
23/// };
24///
25/// struct DebugWriter;
26///
27/// impl CommandOutput for DebugWriter {
28///     fn execute(&mut self, command: Command) {
29///         print!("Register 0b{:08b} ({:?}), ", command.register, command.register);
30///         println!("0b{:08b} ({:?})", command.value, command.value);
31///     }
32/// }
33///
34/// let mut chip = YM2149::new(
35///     DebugWriter{},
36///     2_000_000,
37/// ).expect("Error building chip");
38///
39/// chip.setup_io_and_mixer(
40///     IoPortMixerSettings {
41///         tone_ch_a: true,
42///         ..Default::default()
43///     }
44/// );
45/// ```
46#[derive(Debug)]
47pub struct YM2149<C>
48where
49    C: CommandOutput,
50{
51    command_output: C,
52    master_clock_frequency: u32,
53    pub channel_data: [AudioChannelData; 3],
54    pub last_used_channel: Option<usize>,
55}
56
57impl<C> YM2149<C>
58where
59    C: CommandOutput,
60{
61    /// Create a new struct for the YM2149.
62    pub fn new(command_output: C, master_clock_frequency: u32) -> Result<Self, Error> {
63        match master_clock_frequency {
64            1_000_000..=4_000_000 => Ok(Self {
65                command_output,
66                master_clock_frequency,
67                channel_data: [
68                    AudioChannelData::new(0),
69                    AudioChannelData::new(1),
70                    AudioChannelData::new(2)
71                ],
72                last_used_channel: None
73            }),
74            _ => Err(Error::InvalidClockFrequency(master_clock_frequency)) //"The master_clock_frequency must be between 1MHz-4MHz!")
75        }
76    }
77
78    /// Send a [Command](#Command).
79    pub fn command<R: ValidRegister + Copy>(&mut self, register: R, value: u8) {
80        self.command_output
81            .execute(Command::new(register.address(), value));
82    }
83
84    /// Setup the IO ports and the internal mixer according to the IoPortMixerSettings specified.
85    pub fn setup_io_and_mixer(&mut self, settings: IoPortMixerSettings) {
86        self.channel_data[0].enabled = settings.tone_ch_a;
87        self.channel_data[1].enabled = settings.tone_ch_b;
88        self.channel_data[2].enabled = settings.tone_ch_c;
89
90        self.command(Register::IoPortMixerSettings, settings.as_u8());
91    }
92
93    /// Write a value to one of the chip's [GPIO ports](#IoPort).
94    /// Note: This is a simple helper function, equivalent to ``self.command(port as u8, value);``
95    pub fn write_io(&mut self, port: IoPort, value: u8) {
96        self.command(port as u8, value);
97    }
98
99    /// Set the envelope generator's frequency.
100    pub fn set_envelope_frequency(&mut self, frequency: EnvelopeFrequency) -> Result<u16, Error> {
101        let r: u16 = frequency.as_ep(self.master_clock_frequency)?;
102
103        let rough: u8 = (r >> 8) as u8; // High byte
104        let fine: u8 = r as u8; // Low byte
105
106        self.command(Register::EFreq8bitRoughAdj, rough);
107        self.command(Register::EFreq8bitFineAdj, fine);
108
109        Ok(r)
110    }
111
112    /// Set the envelope generator's shape.
113    pub fn set_envelope_shape(&mut self, envelope: &Envelope) {
114        self.command(0xD, envelope.into());
115    }
116
117    /// Play a tone with a TP of `period` on an [AudioChannel](#AudioChannel).
118    ///
119    /// The formula for the frequency is
120    /// ``f = fMaster / (16 * TP)``, where:
121    ///     - f: target frequency
122    ///     - fMaster: master clock frequency
123    ///     - TP: tone period
124    pub fn tone(&mut self, channel: AudioChannel, period: u16) -> Result<(), Error> {
125        if period > 2_u16.pow(12) {
126            return Err(Error::TonePeriodOutOfRange(period));
127        }
128
129        let bytes: [u8; 2] = period.to_le_bytes();
130        let register_pair_index = self.channel_data[channel.index()].address * 2;
131
132        self.command(register_pair_index, bytes[0]); // Fine adjustment, 8 bits
133        self.command(register_pair_index + 1, bytes[1]); // Rough adjustment, 4 bits
134        self.last_used_channel = Some(channel.index());
135
136        Ok(())
137    }
138
139    /// Play a tone of a given frequency in Hz on an [AudioChannel](#AudioChannel).
140    pub fn tone_hz(&mut self, channel: AudioChannel, frequency: u32) -> Result<(), Error> {
141        if frequency == 0 {
142            return Err(Error::DivisionByZero);
143        }
144
145        let tp: u32 = self.master_clock_frequency / (16 * frequency);
146        self.tone(channel, tp as u16)?; // Take lowest 16 bits
147
148        Ok(())
149    }
150
151    /// Play a [Note](#Note) on an [AudioChannel](#AudioChannel).
152    pub fn play_note(&mut self, channel: AudioChannel, note: &Note) -> Result<(), Error> {
153        self.channel_data[channel.index()].last_note = Some(note.clone());
154
155        self.tone_hz(
156            channel,
157            note.transpose(self.channel_data[channel.index()].pitch_bend).as_hz()
158        )?;
159
160        Ok(())
161    }
162
163    /// Set an AudioChannel's pitch bend (takes a MIDI command).
164    pub fn pitch_bend(&mut self, channel: AudioChannel, byte1: u8, byte2: u8, replay_last: bool) -> Result<f32, Error> {
165        self.channel_data[channel.index()].set_pitch_bend(byte1, byte2);
166        if replay_last {
167            self.replay_last_note(channel)?;
168        }
169
170        Ok(self.channel_data[channel.index()].pitch_bend)
171    }
172
173    /// Replay the last played note on a given channel.
174    pub fn replay_last_note(&mut self, channel: AudioChannel) -> Result<(), Error> {
175        let last_note = self.channel_data[channel.index()].last_note;
176
177        match last_note {
178            Some(last_note) => { self.play_note(channel, &last_note)?; Ok(()) },
179            None => Err(Error::NoLastNote)
180        }
181    }
182
183    /// Play a [Note](#Note) on an [AudioChannel](#AudioChannel) with a given [Envelope](#Envelope).
184    pub fn play_note_with_envelope(
185        &mut self,
186        channel: AudioChannel,
187        note: &Note,
188        with_envelope: &Envelope,
189    ) -> Result<(), Error> {
190        self.play_note(channel, note)?;
191        self.set_envelope_shape(with_envelope);
192        Ok(())
193    }
194
195    /// Set the frequency of the noise generator.
196    ///
197    /// Mask: 0x1F
198    pub fn set_noise_freq(&mut self, frequency: u8) -> Result<(), Error> {
199        if frequency <= 0x1F {
200            self.command(Register::NoiseFreq5bit, frequency);
201            Ok(())
202        } else {
203            Err(Error::NoiseFrequencyOutOfRange(frequency))
204        }
205    }
206
207    /// Set the volume of an [AudioChannel](#AudioChannel).
208    ///
209    /// **Note:** The channel level registers store 5 bits of data per channel.
210    ///
211    /// ---
212    ///
213    /// From the datasheet:
214    /// - Mode M selects whether the level is fixed (when M = 0) or variable (M = 1).
215    /// - When M = 0, the level is determined from one of 16 by level selection signals L3, L2, L1, and L0 which compromise the lower four bits.
216    /// - When M = 1, the level is determined by the 5 bit output of E4, E3, E2, E1, and E0 of the envelope generator of the SSG.
217    ///
218    /// | B7 (MSB)  | B6  | B5  | B4  | B3  | B2  | B1  | B0  |
219    /// |-----------|-----|-----|-----|-----|-----|-----|-----|
220    /// | N/A       | N/A | N/A |  M  | L3  | L2  | L1  | L0  |
221    pub fn level(&mut self, channel: AudioChannel, level: u8) {
222        self.channel_data[channel.index()].level = level;
223        self.command(LEVEL_REGS[channel.index()] as u8, level & 0x1F);
224    }
225
226    // ============================================================
227    // ========================= THE VOID =========================
228    // ============================================================
229    // (All you'll find here is unimplemented / todo functionality)
230
231    #[allow(unused)]
232    /// Reads a value from a given register and outputs it to the data bus.
233    ///
234    /// ---
235    /// # Warning!
236    ///
237    /// Mode::READ makes the chip output 5V to the data bus. It is **STRONGLY** recommended
238    /// to use a level shifter in order to prevent permanent damage to your board.
239    ///
240    /// This method is **unimplemented** *(at least, not for now...)*
241    ///
242    /// Feel free to try implementing it yourself, at your own risk.
243    fn read(&self, register: Register) -> u8 {
244        unimplemented!("Mode::READ and any functions associated with it are not yet usable.");
245    }
246
247    #[allow(unused)]
248    /// Reads a value from a given I/O port and outputs it to the data bus.
249    ///
250    /// ---
251    /// # Warning!
252    ///
253    /// Mode::READ makes the chip output 5V to the data bus. It is **STRONGLY** recommended
254    /// to use a level shifter in order to prevent permanent damage to your board.
255    ///
256    /// This method is **unimplemented** *(at least, not for now...)*
257    ///
258    /// Feel free to try implementing it yourself, at your own risk.
259    fn read_io(&self, port: IoPort) -> u8 {
260        unimplemented!("Mode::READ and any functions associated with it are not yet usable.");
261    }
262}