game_toolkit_dosaudio/
capture.rs1use crate::{Error, OplChip, Result, Tick};
2pub(crate) mod stream;
3pub use stream::MusicCapture;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub struct PortWrite {
8 pub at: Tick,
10 pub port: u16,
12 pub value: u8,
14}
15
16#[derive(Clone, Debug)]
22pub struct Capture {
23 pub(crate) start: Tick,
24 pub(crate) end: Tick,
25 pub(crate) chip: Option<OplChip>,
26 pub(crate) address: [u8; 2],
27 pub(crate) card: Option<(u16, crate::SbModel)>,
28 pub(crate) writes: Vec<PortWrite>,
29}
30impl Capture {
31 pub fn writes(&self) -> &[PortWrite] {
33 &self.writes
34 }
35 pub fn duration(&self) -> Tick {
37 self.end - self.start
38 }
39 pub fn to_dro(&self) -> Result<Vec<u8>> {
44 let chip = self
45 .chip
46 .ok_or(Error::Config("DRO export requires installed OPL hardware"))?;
47 let milliseconds = |at: Tick| -> Result<u32> {
48 let elapsed = at.checked_sub(self.start).ok_or(Error::BackwardsTime)?;
49 u32::try_from(
50 (u128::from(elapsed.0) * u128::from(Tick::HZ_DENOMINATOR) * 1_000
51 + u128::from(Tick::HZ_NUMERATOR) / 2)
52 / u128::from(Tick::HZ_NUMERATOR),
53 )
54 .map_err(|_| Error::TooLarge)
55 };
56 let mut data = Vec::new();
57 let mut address = self.address;
58 let mut bank = 0usize;
59 let mut time = 0u32;
60 for write in &self.writes {
61 for port in crate::bus::map_opl_ports(write.port, self.card)
62 .into_iter()
63 .flatten()
64 {
65 if !(0x388..=0x38b).contains(&port) {
66 continue;
67 }
68 let target = usize::from(port >= 0x38a);
69 if target == 1 && chip == OplChip::Opl2 {
70 continue;
71 }
72 if port & 1 == 0 {
73 address[target] = write.value;
74 continue;
75 }
76 let next = milliseconds(write.at)?;
77 delay(&mut data, next - time);
78 time = next;
79 if bank != target {
80 data.push(if target == 0 { 2 } else { 3 });
81 bank = target;
82 }
83 let register = address[target];
84 if register <= 4 {
85 data.push(4);
86 }
87 data.extend([register, write.value]);
88 }
89 }
90 let end = milliseconds(self.end)?;
91 delay(&mut data, end - time);
92 let size = u32::try_from(data.len()).map_err(|_| Error::TooLarge)?;
93 let mut bytes = Vec::with_capacity(data.len().checked_add(24).ok_or(Error::TooLarge)?);
94 bytes.extend(b"DBRAWOPL");
95 bytes.extend(0u16.to_le_bytes());
96 bytes.extend(1u16.to_le_bytes());
97 bytes.extend(end.to_le_bytes());
98 bytes.extend(size.to_le_bytes());
99 bytes.extend(
100 match chip {
101 OplChip::Opl2 => 0u32,
102 OplChip::Opl3 => 1,
103 OplChip::DualOpl2 => 2,
104 }
105 .to_le_bytes(),
106 );
107 bytes.extend(data);
108 Ok(bytes)
109 }
110}
111
112fn delay(data: &mut Vec<u8>, mut milliseconds: u32) {
113 while milliseconds > 0 {
114 let amount = milliseconds.min(65_536);
115 if amount <= 256 {
116 data.extend([0, (amount - 1) as u8]);
117 } else {
118 data.push(1);
119 data.extend(((amount - 1) as u16).to_le_bytes());
120 }
121 milliseconds -= amount;
122 }
123}