2023-07-12 21:18:02 +10:00
|
|
|
#![cfg_attr(not(feature = "std"), no_std)]
|
2023-07-13 00:38:09 +10:00
|
|
|
|
|
|
|
use agb_fixnum::Num;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Track<'a> {
|
|
|
|
pub samples: &'a [Sample<'a>],
|
|
|
|
pub pattern_data: &'a [PatternSlot],
|
|
|
|
pub patterns: &'a [Pattern],
|
2023-07-13 02:36:41 +10:00
|
|
|
|
2023-07-13 03:52:29 +10:00
|
|
|
pub num_channels: usize,
|
2023-07-13 02:36:41 +10:00
|
|
|
pub frames_per_step: u16,
|
2023-07-13 00:38:09 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Sample<'a> {
|
|
|
|
pub data: &'a [u8],
|
2023-07-13 02:36:41 +10:00
|
|
|
pub should_loop: bool,
|
2023-07-13 00:38:09 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Pattern {
|
2023-07-13 02:36:41 +10:00
|
|
|
pub length: usize,
|
|
|
|
pub start_position: usize,
|
2023-07-13 00:38:09 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PatternSlot {
|
|
|
|
pub volume: Num<i16, 4>,
|
|
|
|
pub speed: Num<u32, 8>,
|
|
|
|
pub panning: Num<i16, 4>,
|
|
|
|
pub sample: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "quote")]
|
|
|
|
impl<'a> quote::ToTokens for Track<'a> {
|
|
|
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
|
|
|
use quote::{quote, TokenStreamExt};
|
|
|
|
|
2023-07-13 02:36:41 +10:00
|
|
|
let Track {
|
|
|
|
samples,
|
|
|
|
pattern_data,
|
|
|
|
patterns,
|
|
|
|
frames_per_step,
|
2023-07-13 03:52:29 +10:00
|
|
|
num_channels,
|
2023-07-13 02:36:41 +10:00
|
|
|
} = self;
|
2023-07-13 00:38:09 +10:00
|
|
|
|
|
|
|
tokens.append_all(quote! {
|
|
|
|
{
|
|
|
|
use agb_tracker_interop::*;
|
|
|
|
|
|
|
|
const SAMPLES: &[Sample<'static>] = &[#(#samples),*];
|
|
|
|
const PATTERN_DATA: &[PatternSlot] = &[#(#pattern_data),*];
|
|
|
|
const PATTERNS: &[Pattern] = &[#(#patterns),*];
|
|
|
|
|
|
|
|
Track {
|
|
|
|
samples: SAMPLES,
|
|
|
|
pattern_data: PATTERN_DATA,
|
|
|
|
patterns: PATTERNS,
|
2023-07-13 02:36:41 +10:00
|
|
|
|
|
|
|
frames_per_step: #frames_per_step,
|
2023-07-13 03:52:29 +10:00
|
|
|
num_channels: #num_channels,
|
2023-07-13 00:38:09 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 02:36:41 +10:00
|
|
|
#[cfg(feature = "quote")]
|
|
|
|
struct ByteString<'a>(&'a [u8]);
|
|
|
|
#[cfg(feature = "quote")]
|
|
|
|
impl quote::ToTokens for ByteString<'_> {
|
|
|
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
|
|
|
use quote::TokenStreamExt;
|
|
|
|
|
|
|
|
tokens.append(proc_macro2::Literal::byte_string(self.0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 00:38:09 +10:00
|
|
|
#[cfg(feature = "quote")]
|
|
|
|
impl<'a> quote::ToTokens for Sample<'a> {
|
|
|
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
|
|
|
use quote::{quote, TokenStreamExt};
|
|
|
|
|
2023-07-13 02:36:41 +10:00
|
|
|
let self_as_u8s: Vec<_> = self.data.iter().map(|i| *i as u8).collect();
|
|
|
|
let samples = ByteString(&self_as_u8s);
|
|
|
|
let should_loop = self.should_loop;
|
2023-07-13 00:38:09 +10:00
|
|
|
|
|
|
|
tokens.append_all(quote! {
|
|
|
|
{
|
|
|
|
use agb_tracker_interop::*;
|
|
|
|
|
2023-07-13 02:36:41 +10:00
|
|
|
#[repr(align(4))]
|
|
|
|
struct AlignmentWrapper<const N: usize>([u8; N]);
|
|
|
|
|
|
|
|
const SAMPLE_DATA: &[u8] = &AlignmentWrapper(*#samples).0;
|
|
|
|
agb_tracker_interop::Sample { data: SAMPLE_DATA, should_loop: #should_loop }
|
2023-07-13 00:38:09 +10:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "quote")]
|
|
|
|
impl quote::ToTokens for PatternSlot {
|
|
|
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
|
|
|
use quote::{quote, TokenStreamExt};
|
|
|
|
|
|
|
|
let PatternSlot {
|
|
|
|
volume,
|
|
|
|
speed,
|
|
|
|
panning,
|
|
|
|
sample,
|
|
|
|
} = &self;
|
|
|
|
|
|
|
|
let volume = volume.to_raw();
|
|
|
|
let speed = speed.to_raw();
|
|
|
|
let panning = panning.to_raw();
|
|
|
|
|
|
|
|
tokens.append_all(quote! {
|
|
|
|
{
|
|
|
|
use agb_tracker::__private::*;
|
|
|
|
use agb::fixnum::Num;
|
|
|
|
|
|
|
|
PatternSlot {
|
|
|
|
volume: Num::from_raw(#volume),
|
|
|
|
speed: Num::from_raw(#speed),
|
|
|
|
panning: Num::from_raw(#panning),
|
|
|
|
sample: #sample,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "quote")]
|
|
|
|
impl quote::ToTokens for Pattern {
|
|
|
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
|
|
|
use quote::{quote, TokenStreamExt};
|
|
|
|
|
2023-07-13 02:36:41 +10:00
|
|
|
let Pattern {
|
|
|
|
length,
|
|
|
|
start_position,
|
|
|
|
} = self;
|
2023-07-13 00:38:09 +10:00
|
|
|
|
|
|
|
tokens.append_all(quote! {
|
|
|
|
{
|
|
|
|
use agb_tracker_interop::*;
|
|
|
|
|
|
|
|
Pattern {
|
2023-07-13 02:36:41 +10:00
|
|
|
length: #length,
|
|
|
|
start_position: #start_position,
|
2023-07-13 00:38:09 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|