-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Taken from Neotron-Apps.
- Loading branch information
Showing
12 changed files
with
1,051 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
[workspace] | ||
members = [ | ||
"neotron-os", | ||
"utilities/flames", | ||
"utilities/*", | ||
] | ||
resolver = "2" | ||
exclude = [ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "neoplay" | ||
version = "0.1.0" | ||
edition = "2021" | ||
license = "MIT OR Apache-2.0" | ||
authors = ["Jonathan 'theJPster' Pallant <[email protected]>"] | ||
description = "4-channel ProTracker player for Neotro" | ||
|
||
[dependencies] | ||
grounded = { version = "0.2.0", features = ["critical-section", "cas"] } | ||
neotracker = { git = "https://github.com/thejpster/neotracker.git", rev = "2ee7a85006a9461b876bdf47e45b6105437a38f6" } | ||
neotron-sdk = { workspace = true } | ||
|
||
# See workspace for profile settings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Neoplay | ||
|
||
A ProTracker MOD player for the Neotron Pico. | ||
|
||
Runs at 11,025 Hz, quadrupling samples for the audio codec which runs at 44,100 Hz. | ||
|
||
```console | ||
$ cargo build --release --target=thumbv6m-none-eabi | ||
$ cp ../target/thumbv6m-none-eabi/release/neoplay /media/USER/SDCARD/NEOPLAY.ELF | ||
|
||
``` | ||
|
||
```console | ||
> load neoplay.elf | ||
> run airwolf.mod | ||
Loading "airwolf.mod" | ||
audio 44100, SixteenBitStereo | ||
Playing "airwolf.mod" | ||
|
||
000 000000 12 00fe 0f04|-- ---- ----|-- ---- ----|-- ---- ----| | ||
000 000001 -- ---- ----|-- ---- ----|-- ---- ----|-- ---- ----| | ||
000 000002 -- ---- ----|-- ---- ----|-- ---- ----|-- ---- ----| | ||
000 000003 -- ---- ----|-- ---- ----|-- ---- ----|-- ---- ----| | ||
etc | ||
``` | ||
|
||
Here's a video of it in action: https://youtu.be/ONZhDrZsmDU |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fn main() { | ||
println!("cargo:rustc-link-arg-bin=neoplay=-Tneotron-cortex-m.ld"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#![cfg_attr(target_os = "none", no_std)] | ||
#![cfg_attr(target_os = "none", no_main)] | ||
|
||
use core::{fmt::Write, ptr::addr_of_mut}; | ||
|
||
const FILE_BUFFER_LEN: usize = 192 * 1024; | ||
static mut FILE_BUFFER: [u8; FILE_BUFFER_LEN] = [0u8; FILE_BUFFER_LEN]; | ||
|
||
mod player; | ||
|
||
#[cfg(not(target_os = "none"))] | ||
fn main() { | ||
neotron_sdk::init(); | ||
} | ||
|
||
#[no_mangle] | ||
extern "C" fn neotron_main() -> i32 { | ||
if let Err(e) = real_main() { | ||
let mut stdout = neotron_sdk::stdout(); | ||
let _ = writeln!(stdout, "Error: {:?}", e); | ||
1 | ||
} else { | ||
0 | ||
} | ||
} | ||
|
||
fn real_main() -> Result<(), neotron_sdk::Error> { | ||
let mut stdout = neotron_sdk::stdout(); | ||
let stdin = neotron_sdk::stdin(); | ||
let Some(filename) = neotron_sdk::arg(0) else { | ||
return Err(neotron_sdk::Error::InvalidArg); | ||
}; | ||
let _ = writeln!(stdout, "Loading {:?}...", filename); | ||
let path = neotron_sdk::path::Path::new(&filename)?; | ||
let f = neotron_sdk::File::open(path, neotron_sdk::Flags::empty())?; | ||
let file_buffer = unsafe { | ||
let file_buffer = &mut *addr_of_mut!(FILE_BUFFER); | ||
let n = f.read(file_buffer)?; | ||
&file_buffer[0..n] | ||
}; | ||
drop(f); | ||
// Set 16-bit stereo, 44.1 kHz | ||
let dsp_path = neotron_sdk::path::Path::new("AUDIO:")?; | ||
let dsp = neotron_sdk::File::open(dsp_path, neotron_sdk::Flags::empty())?; | ||
if dsp.ioctl(1, 3 << 60 | 44100).is_err() { | ||
let _ = writeln!(stdout, "Failed to configure audio"); | ||
return neotron_sdk::Result::Err(neotron_sdk::Error::DeviceSpecific); | ||
} | ||
|
||
let mut player = match player::Player::new(file_buffer, 44100) { | ||
Ok(player) => player, | ||
Err(e) => { | ||
let _ = writeln!(stdout, "Failed to create player: {:?}", e); | ||
return Err(neotron_sdk::Error::InvalidArg); | ||
} | ||
}; | ||
|
||
let _ = writeln!(stdout, "Playing {:?}...", filename); | ||
let mut sample_buffer = [0u8; 1024]; | ||
// loop some some silence to give us a head-start | ||
for _i in 0..11 { | ||
let _ = dsp.write(&sample_buffer); | ||
} | ||
|
||
loop { | ||
for chunk in sample_buffer.chunks_exact_mut(4) { | ||
let (left, right) = player.next_sample(&mut stdout); | ||
let left_bytes = left.to_le_bytes(); | ||
let right_bytes = right.to_le_bytes(); | ||
chunk[0] = left_bytes[0]; | ||
chunk[1] = left_bytes[1]; | ||
chunk[2] = right_bytes[0]; | ||
chunk[3] = right_bytes[1]; | ||
} | ||
let _ = dsp.write(&sample_buffer); | ||
let mut in_buf = [0u8; 1]; | ||
if player.is_finished() { | ||
break; | ||
} | ||
if stdin.read(&mut in_buf).is_ok() && in_buf[0].to_ascii_lowercase() == b'q' { | ||
break; | ||
} | ||
} | ||
|
||
let _ = writeln!(stdout, "Bye!"); | ||
|
||
Ok(()) | ||
} |
Oops, something went wrong.