Implemented audio

This commit is contained in:
BayThylacine 2025-02-23 11:47:06 +11:00
parent 3775147c84
commit 284ebae8fa
3 changed files with 346 additions and 14 deletions

250
Cargo.lock generated
View File

@ -8,6 +8,7 @@ version = "0.1.0"
dependencies = [
"clap",
"clap_derive",
"cpal",
"pixels",
"rand",
"tao",
@ -42,6 +43,28 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "alsa"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
dependencies = [
"alsa-sys",
"bitflags 2.8.0",
"cfg-if",
"libc",
]
[[package]]
name = "alsa-sys"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
dependencies = [
"libc",
"pkg-config",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
@ -145,6 +168,24 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bindgen"
version = "0.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
dependencies = [
"bitflags 2.8.0",
"cexpr",
"clang-sys",
"itertools",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.98",
]
[[package]]
name = "bit-set"
version = "0.5.3"
@ -233,6 +274,8 @@ version = "1.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
dependencies = [
"jobserver",
"libc",
"shlex",
]
@ -242,6 +285,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-expr"
version = "0.15.8"
@ -264,6 +316,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading 0.8.6",
]
[[package]]
name = "clap"
version = "4.5.28"
@ -452,6 +515,49 @@ dependencies = [
"libc",
]
[[package]]
name = "coreaudio-rs"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace"
dependencies = [
"bitflags 1.3.2",
"core-foundation-sys",
"coreaudio-sys",
]
[[package]]
name = "coreaudio-sys"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b"
dependencies = [
"bindgen",
]
[[package]]
name = "cpal"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779"
dependencies = [
"alsa",
"core-foundation-sys",
"coreaudio-rs",
"dasp_sample",
"jni",
"js-sys",
"libc",
"mach2",
"ndk 0.8.0",
"ndk-context",
"oboe",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows 0.54.0",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.14"
@ -478,6 +584,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "dasp_sample"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
[[package]]
name = "dispatch"
version = "0.2.0"
@ -524,6 +636,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "equivalent"
version = "1.0.1"
@ -826,6 +944,12 @@ dependencies = [
"system-deps",
]
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "glow"
version = "0.13.1"
@ -1166,6 +1290,15 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "jni"
version = "0.21.1"
@ -1188,6 +1321,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jobserver"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.77"
@ -1269,6 +1411,15 @@ version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "mach2"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
dependencies = [
"libc",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
@ -1317,6 +1468,12 @@ dependencies = [
"paste",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "naga"
version = "0.19.2"
@ -1337,6 +1494,20 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "ndk"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
dependencies = [
"bitflags 2.8.0",
"jni-sys",
"log",
"ndk-sys 0.5.0+25.2.9519653",
"num_enum",
"thiserror",
]
[[package]]
name = "ndk"
version = "0.9.0"
@ -1376,6 +1547,16 @@ dependencies = [
"jni-sys",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@ -1386,6 +1567,17 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-derive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.98",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@ -1435,6 +1627,29 @@ dependencies = [
"cc",
]
[[package]]
name = "oboe"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb"
dependencies = [
"jni",
"ndk 0.8.0",
"ndk-context",
"num-derive",
"num-traits",
"oboe-sys",
]
[[package]]
name = "oboe-sys"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d"
dependencies = [
"cc",
]
[[package]]
name = "once_cell"
version = "1.20.3"
@ -1943,7 +2158,7 @@ dependencies = [
"lazy_static",
"libc",
"log",
"ndk",
"ndk 0.9.0",
"ndk-context",
"ndk-sys 0.6.0+11769913",
"objc",
@ -2476,6 +2691,16 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
dependencies = [
"windows-core 0.54.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.58.0"
@ -2495,6 +2720,16 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
dependencies = [
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.58.0"
@ -2503,7 +2738,7 @@ checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [
"windows-implement",
"windows-interface",
"windows-result",
"windows-result 0.2.0",
"windows-strings",
"windows-targets 0.52.6",
]
@ -2530,6 +2765,15 @@ dependencies = [
"syn 2.0.98",
]
[[package]]
name = "windows-result"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.2.0"
@ -2545,7 +2789,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [
"windows-result",
"windows-result 0.2.0",
"windows-targets 0.52.6",
]

View File

@ -11,3 +11,4 @@ tao = "0.31.1"
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
rand = "0.9.0"
cpal = "0.15.3"

View File

@ -14,10 +14,14 @@ use tao::{
use tao::dpi::LogicalSize;
use tracing::{info, error};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use rand::prelude::*;
use tao::keyboard::Key;
use std::time::{Duration, Instant};
use cpal::{SampleFormat, SampleRate, Stream, SupportedStreamConfig};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use rand::seq::index::sample;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
const MODERNSHIFT: bool = false;
const OLDJUMP: bool = true;
@ -30,6 +34,81 @@ struct Args {
file: PathBuf,
}
struct AudioPlayer {
stream: Stream,
}
struct Oscilator {
sample_index: f32,
volume: f32,
}
impl AudioPlayer {
fn make(rx: Receiver<f32>) -> Self {
let host = cpal::default_host();
let device = host
.default_output_device()
.expect("no output device available");
let config = device.supported_output_configs().expect("error while querying config").find(|config| config.sample_format() == SampleFormat::F32);
if config.is_none() {panic!("no supported config found");}
let config = config.unwrap();
if config.min_sample_rate() > SampleRate(48000) || config.max_sample_rate() < SampleRate(48000) {
//("{:?},{:?}", config.min_sample_rate(), config.max_sample_rate());
panic!("sample rate out of range");
}
let format = SupportedStreamConfig::new(
config.channels(),
SampleRate(48000),
config.buffer_size().clone(),
SampleFormat::F32
);
//let time_at_start = Instant::now();
let mut oscilator = Oscilator{sample_index: 0.0, volume: 0.0};
let stream = device.build_output_stream(
&format.config(),
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
//let time_since_start = Instant::now().duration_since(time_at_start).as_secs_f32();
if let Ok(vol) = rx.try_recv() {
oscilator.volume = vol as f32;
}
process_frame(data, config.channels().into(), &mut oscilator);
},
(|err| error!("Error while creating output stream, {}", err)),
None,
);
Self {
stream: stream.expect("no stream available"),
}
}
fn run(&mut self) {
self.stream.play().unwrap();
}
}
fn process_frame(output: &mut [f32], channels: usize, oscilator: &mut Oscilator) {
for frame in output.chunks_mut(channels) {
let value = oscilator.tick() * oscilator.volume;
for sample in frame.iter_mut() {
*sample = value;
}
}
}
impl Oscilator {
fn tick(&mut self) -> f32 {
self.sample_index = (self.sample_index + 1.0) % 48000.0;
let two_pi = 2.0 * std::f32::consts::PI;
(self.sample_index * 440.0 * two_pi/48000.0).sin()
}
}
#[derive(Copy, Clone)]
struct Chip8 {
display: [u64; 32],
@ -78,9 +157,12 @@ impl Chip8 {
self
}
fn draw(&mut self, frame: &mut [u8], dimensions: (u32, u32)) -> Self {
fn draw(&mut self, frame: &mut [u8], dimensions: (u32, u32), tx: &SyncSender<f32>) -> Self {
if self.sound_timer != 0 {
self.sound_timer -= 1;
tx.send(0.5).unwrap();
} else {
tx.send(0.0).unwrap();
}
if self.delay_timer != 0 {
self.delay_timer -= 1;
@ -219,10 +301,10 @@ impl Chip8 {
0x05 => {
let r1 = self.registers[opcodes[1] as usize];
let r2 = self.registers[opcodes[2] as usize];
info!("{},{}", r1 , r2);
//info!("{},{}", r1 , r2);
let no_underflow = (r1 >= r2);
if no_underflow {
info!("{}",r1 - r2);
//info!("{}",r1 - r2);
self.registers[opcodes[1] as usize] = r1 - r2;
} else {
self.registers[opcodes[1] as usize] = 255 - ((r2 - r1) - 1);
@ -493,6 +575,7 @@ fn main() {
let args = Args::parse();
let mut chip8 = Chip8::new().insert_font().load_file(args.file);
let (tx, rx) = sync_channel(1);
println!("ram: {:?}", chip8.ram);
@ -501,7 +584,7 @@ fn main() {
let window = { let window = WindowBuilder::new()
.with_title("Chip8 Emulator")
.with_inner_size(LogicalSize::new(320, 240))
.with_min_inner_size(LogicalSize::new(320, 240))
.with_min_inner_size(LogicalSize::new(600, 300))
.build(&event_loop)
.unwrap();
Arc::new(window)
@ -513,8 +596,12 @@ fn main() {
Pixels::new(window_size.width, window_size.height, surface_texture).unwrap()
};
let mut audio = AudioPlayer::make(rx);
audio.run();
let test: u64 = 1;
info!("{}", get_bit(test, 0));
//info!("{}", get_bit(test, 0));
let mut start = Instant::now();
event_loop.run(move |event, _, control_flow| {
match event {
@ -599,14 +686,14 @@ fn main() {
window.request_redraw();
}
Event::RedrawRequested(_) => {
chip8.draw(pixels.frame_mut(), (window.inner_size().width, window.inner_size().height));
chip8.draw(pixels.frame_mut(), (window.inner_size().width, window.inner_size().height), &tx);
if let Err(err) = pixels.render() {
error!("pixels.render");
*control_flow = ControlFlow::Exit;
}
let duration = start.elapsed();
info!("{:?}", duration);
start = Instant::now();
//let duration = start.elapsed();
//info!("{:?}", duration);
//start = Instant::now();
}
_ => {}
}