bitcomposer-emu 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ target/
2
+ dist/
@@ -0,0 +1,252 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "autocfg"
7
+ version = "1.5.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
10
+
11
+ [[package]]
12
+ name = "bitcomposer-emu"
13
+ version = "0.3.1"
14
+ dependencies = [
15
+ "pyo3",
16
+ "serde_json",
17
+ ]
18
+
19
+ [[package]]
20
+ name = "cfg-if"
21
+ version = "1.0.5"
22
+ source = "registry+https://github.com/rust-lang/crates.io-index"
23
+ checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
24
+
25
+ [[package]]
26
+ name = "heck"
27
+ version = "0.5.0"
28
+ source = "registry+https://github.com/rust-lang/crates.io-index"
29
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
30
+
31
+ [[package]]
32
+ name = "indoc"
33
+ version = "2.0.8"
34
+ source = "registry+https://github.com/rust-lang/crates.io-index"
35
+ checksum = "a37b2691796cffeb8a8cd305ac66e65841559f147f4e63231d0eafa4db5384d1"
36
+ dependencies = [
37
+ "rustversion",
38
+ ]
39
+
40
+ [[package]]
41
+ name = "itoa"
42
+ version = "1.0.18"
43
+ source = "registry+https://github.com/rust-lang/crates.io-index"
44
+ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
45
+
46
+ [[package]]
47
+ name = "libc"
48
+ version = "0.2.191"
49
+ source = "registry+https://github.com/rust-lang/crates.io-index"
50
+ checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
51
+
52
+ [[package]]
53
+ name = "memchr"
54
+ version = "2.8.3"
55
+ source = "registry+https://github.com/rust-lang/crates.io-index"
56
+ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
57
+
58
+ [[package]]
59
+ name = "memoffset"
60
+ version = "0.9.1"
61
+ source = "registry+https://github.com/rust-lang/crates.io-index"
62
+ checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
63
+ dependencies = [
64
+ "autocfg",
65
+ ]
66
+
67
+ [[package]]
68
+ name = "once_cell"
69
+ version = "1.21.4"
70
+ source = "registry+https://github.com/rust-lang/crates.io-index"
71
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
72
+
73
+ [[package]]
74
+ name = "portable-atomic"
75
+ version = "1.15.0"
76
+ source = "registry+https://github.com/rust-lang/crates.io-index"
77
+ checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
78
+
79
+ [[package]]
80
+ name = "proc-macro2"
81
+ version = "1.0.107"
82
+ source = "registry+https://github.com/rust-lang/crates.io-index"
83
+ checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
84
+ dependencies = [
85
+ "unicode-ident",
86
+ ]
87
+
88
+ [[package]]
89
+ name = "pyo3"
90
+ version = "0.23.5"
91
+ source = "registry+https://github.com/rust-lang/crates.io-index"
92
+ checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872"
93
+ dependencies = [
94
+ "cfg-if",
95
+ "indoc",
96
+ "libc",
97
+ "memoffset",
98
+ "once_cell",
99
+ "portable-atomic",
100
+ "pyo3-build-config",
101
+ "pyo3-ffi",
102
+ "pyo3-macros",
103
+ "unindent",
104
+ ]
105
+
106
+ [[package]]
107
+ name = "pyo3-build-config"
108
+ version = "0.23.5"
109
+ source = "registry+https://github.com/rust-lang/crates.io-index"
110
+ checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb"
111
+ dependencies = [
112
+ "once_cell",
113
+ "target-lexicon",
114
+ ]
115
+
116
+ [[package]]
117
+ name = "pyo3-ffi"
118
+ version = "0.23.5"
119
+ source = "registry+https://github.com/rust-lang/crates.io-index"
120
+ checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d"
121
+ dependencies = [
122
+ "libc",
123
+ "pyo3-build-config",
124
+ ]
125
+
126
+ [[package]]
127
+ name = "pyo3-macros"
128
+ version = "0.23.5"
129
+ source = "registry+https://github.com/rust-lang/crates.io-index"
130
+ checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da"
131
+ dependencies = [
132
+ "proc-macro2",
133
+ "pyo3-macros-backend",
134
+ "quote",
135
+ "syn 2.0.119",
136
+ ]
137
+
138
+ [[package]]
139
+ name = "pyo3-macros-backend"
140
+ version = "0.23.5"
141
+ source = "registry+https://github.com/rust-lang/crates.io-index"
142
+ checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028"
143
+ dependencies = [
144
+ "heck",
145
+ "proc-macro2",
146
+ "pyo3-build-config",
147
+ "quote",
148
+ "syn 2.0.119",
149
+ ]
150
+
151
+ [[package]]
152
+ name = "quote"
153
+ version = "1.0.47"
154
+ source = "registry+https://github.com/rust-lang/crates.io-index"
155
+ checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
156
+ dependencies = [
157
+ "proc-macro2",
158
+ ]
159
+
160
+ [[package]]
161
+ name = "rustversion"
162
+ version = "1.0.23"
163
+ source = "registry+https://github.com/rust-lang/crates.io-index"
164
+ checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
165
+
166
+ [[package]]
167
+ name = "serde"
168
+ version = "1.0.229"
169
+ source = "registry+https://github.com/rust-lang/crates.io-index"
170
+ checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
171
+ dependencies = [
172
+ "serde_core",
173
+ ]
174
+
175
+ [[package]]
176
+ name = "serde_core"
177
+ version = "1.0.229"
178
+ source = "registry+https://github.com/rust-lang/crates.io-index"
179
+ checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
180
+ dependencies = [
181
+ "serde_derive",
182
+ ]
183
+
184
+ [[package]]
185
+ name = "serde_derive"
186
+ version = "1.0.229"
187
+ source = "registry+https://github.com/rust-lang/crates.io-index"
188
+ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
189
+ dependencies = [
190
+ "proc-macro2",
191
+ "quote",
192
+ "syn 3.0.9",
193
+ ]
194
+
195
+ [[package]]
196
+ name = "serde_json"
197
+ version = "1.0.154"
198
+ source = "registry+https://github.com/rust-lang/crates.io-index"
199
+ checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6"
200
+ dependencies = [
201
+ "itoa",
202
+ "memchr",
203
+ "serde",
204
+ "serde_core",
205
+ "zmij",
206
+ ]
207
+
208
+ [[package]]
209
+ name = "syn"
210
+ version = "2.0.119"
211
+ source = "registry+https://github.com/rust-lang/crates.io-index"
212
+ checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
213
+ dependencies = [
214
+ "proc-macro2",
215
+ "quote",
216
+ "unicode-ident",
217
+ ]
218
+
219
+ [[package]]
220
+ name = "syn"
221
+ version = "3.0.9"
222
+ source = "registry+https://github.com/rust-lang/crates.io-index"
223
+ checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
224
+ dependencies = [
225
+ "proc-macro2",
226
+ "quote",
227
+ "unicode-ident",
228
+ ]
229
+
230
+ [[package]]
231
+ name = "target-lexicon"
232
+ version = "0.12.16"
233
+ source = "registry+https://github.com/rust-lang/crates.io-index"
234
+ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
235
+
236
+ [[package]]
237
+ name = "unicode-ident"
238
+ version = "1.0.27"
239
+ source = "registry+https://github.com/rust-lang/crates.io-index"
240
+ checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
241
+
242
+ [[package]]
243
+ name = "unindent"
244
+ version = "0.2.4"
245
+ source = "registry+https://github.com/rust-lang/crates.io-index"
246
+ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
247
+
248
+ [[package]]
249
+ name = "zmij"
250
+ version = "1.0.23"
251
+ source = "registry+https://github.com/rust-lang/crates.io-index"
252
+ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
@@ -0,0 +1,28 @@
1
+ [package]
2
+ name = "bitcomposer-emu"
3
+ version = "0.3.1"
4
+ edition = "2021"
5
+ license = "MIT"
6
+ description = "The SNES sound CPU (SPC700) and SNES chip (S-DSP) emulator behind bitComposer's SPC import"
7
+ repository = "https://github.com/CatDogBark/bitComposer"
8
+ publish = false
9
+
10
+ [lib]
11
+ name = "bitcomposer_emu"
12
+ crate-type = ["cdylib", "rlib"]
13
+
14
+ [features]
15
+ # The Python module. Off for `cargo test`, which then needs no Python at all;
16
+ # the wheel build (pyproject.toml) turns it on.
17
+ python = ["dep:pyo3"]
18
+
19
+ [dependencies]
20
+ pyo3 = { version = "0.23", features = ["abi3-py310"], optional = true }
21
+
22
+ [dev-dependencies]
23
+ serde_json = "1"
24
+
25
+ [profile.release]
26
+ opt-level = 3
27
+ lto = "fat"
28
+ codegen-units = 1
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.4
2
+ Name: bitcomposer-emu
3
+ Version: 0.3.1
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: 3
6
+ Summary: The SNES sound CPU and SNES chip emulator behind bitComposer's SPC import
7
+ Author-email: CatDogBark <catdogbark@pm.me>
8
+ License: MIT
9
+ Requires-Python: >=3.10
@@ -0,0 +1,56 @@
1
+ //! Run an SPC snapshot for N seconds of song and print what the driver did:
2
+ //! cargo run --release --example run_spc -- song.spc [seconds] [--wav out.wav] [--cpu-only]
3
+ use bitcomposer_emu::spc::{self, CLOCK};
4
+ use std::time::Instant;
5
+
6
+ fn main() {
7
+ let args: Vec<String> = std::env::args().collect();
8
+ let path = &args[1];
9
+ let seconds: f64 = args.get(2).and_then(|s| s.parse().ok()).unwrap_or(10.0);
10
+ let data = std::fs::read(path).expect("read the file");
11
+ let (mut cpu, mut bus) = spc::load(&data).expect("an SPC file");
12
+ let wav = args.iter().position(|a| a == "--wav").map(|i| args[i + 1].clone());
13
+ if wav.is_some() {
14
+ bus.dsp.audio = Some(Vec::new());
15
+ }
16
+ let t = Instant::now();
17
+ let budget = (CLOCK as f64 * seconds) as u64;
18
+ let n = if args.iter().any(|a| a == "--cpu-only") { cpu.run(&mut bus, budget) } else { spc::run(&mut cpu, &mut bus, budget) };
19
+ let dt = t.elapsed().as_secs_f64();
20
+ let song = cpu.cycles as f64 / CLOCK as f64;
21
+ let kon: Vec<_> = bus.log.iter().filter(|w| w.reg == 0x4C && w.value != 0).collect();
22
+ let notes: u32 = kon.iter().map(|w| w.value.count_ones()).sum();
23
+ println!("{}", path.rsplit('/').next().unwrap());
24
+ println!(" {song:.1} s of song in {dt:.4} s wall: {:.0}x real time; {:.0} M instructions/s",
25
+ song / dt, n as f64 / dt / 1e6);
26
+ println!(" {} SNES chip writes, {} key-on writes ({notes} notes); halted={}", bus.log.len(), kon.len(), cpu.halted);
27
+ let first: Vec<String> = kon.iter().take(6).map(|w| format!("{:.2}", w.cycle as f64 / CLOCK as f64)).collect();
28
+ println!(" first notes at {} s", first.join(", "));
29
+ let live: u64 = (0..8).map(|v| bus.dsp_reads[v * 0x10 + 8] + bus.dsp_reads[v * 0x10 + 9]).sum::<u64>() + bus.dsp_reads[0x7C];
30
+ println!(" live SNES chip state read back {live} times");
31
+ if let (Some(path), Some(pcm)) = (wav, bus.dsp.audio.as_ref()) {
32
+ write_wav(&path, pcm);
33
+ println!(" wrote {path} ({:.1} s)", pcm.len() as f64 / 64000.0);
34
+ }
35
+ }
36
+
37
+ fn write_wav(path: &str, pcm: &[i16]) {
38
+ let mut out = Vec::with_capacity(44 + pcm.len() * 2);
39
+ let data = (pcm.len() * 2) as u32;
40
+ out.extend_from_slice(b"RIFF");
41
+ out.extend_from_slice(&(36 + data).to_le_bytes());
42
+ out.extend_from_slice(b"WAVEfmt ");
43
+ out.extend_from_slice(&16u32.to_le_bytes());
44
+ out.extend_from_slice(&1u16.to_le_bytes());
45
+ out.extend_from_slice(&2u16.to_le_bytes());
46
+ out.extend_from_slice(&32000u32.to_le_bytes());
47
+ out.extend_from_slice(&(32000u32 * 4).to_le_bytes());
48
+ out.extend_from_slice(&4u16.to_le_bytes());
49
+ out.extend_from_slice(&16u16.to_le_bytes());
50
+ out.extend_from_slice(b"data");
51
+ out.extend_from_slice(&data.to_le_bytes());
52
+ for s in pcm {
53
+ out.extend_from_slice(&s.to_le_bytes());
54
+ }
55
+ std::fs::write(path, out).expect("write the WAV");
56
+ }
@@ -0,0 +1,16 @@
1
+ [build-system]
2
+ requires = ["maturin>=1.7,<2"]
3
+ build-backend = "maturin"
4
+
5
+ [project]
6
+ name = "bitcomposer-emu"
7
+ version = "0.3.1"
8
+ description = "The SNES sound CPU and SNES chip emulator behind bitComposer's SPC import"
9
+ requires-python = ">=3.10"
10
+ license = { text = "MIT" }
11
+ authors = [{ name = "CatDogBark", email = "catdogbark@pm.me" }]
12
+ classifiers = ["Programming Language :: Rust", "Programming Language :: Python :: 3"]
13
+
14
+ [tool.maturin]
15
+ features = ["python", "pyo3/extension-module"]
16
+ module-name = "bitcomposer_emu"