mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Make agb-xm-core return the interop rather than the tokens
This commit is contained in:
parent
5829d71b6b
commit
d00de7b2a4
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
error::Error,
|
error::Error,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
|
@ -386,7 +387,7 @@ pub fn parse_midi(midi_info: &MidiInfo) -> TokenStream {
|
||||||
let samples: Vec<_> = samples
|
let samples: Vec<_> = samples
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sample| Sample {
|
.map(|sample| Sample {
|
||||||
data: &sample.data,
|
data: sample.data.clone().into(),
|
||||||
should_loop: sample.restart_point.is_some(),
|
should_loop: sample.restart_point.is_some(),
|
||||||
restart_point: sample.restart_point.unwrap_or(0),
|
restart_point: sample.restart_point.unwrap_or(0),
|
||||||
volume: 256.into(),
|
volume: 256.into(),
|
||||||
|
@ -409,7 +410,7 @@ pub fn parse_midi(midi_info: &MidiInfo) -> TokenStream {
|
||||||
let envelopes: Vec<_> = envelopes
|
let envelopes: Vec<_> = envelopes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|envelope| Envelope {
|
.map(|envelope| Envelope {
|
||||||
amount: &envelope.amounts,
|
amount: envelope.amounts.clone().into(),
|
||||||
sustain: Some(envelope.amounts.len() - 1),
|
sustain: Some(envelope.amounts.len() - 1),
|
||||||
loop_start: None,
|
loop_start: None,
|
||||||
loop_end: None,
|
loop_end: None,
|
||||||
|
@ -417,14 +418,14 @@ pub fn parse_midi(midi_info: &MidiInfo) -> TokenStream {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let track = Track {
|
let track = Track {
|
||||||
samples: &samples,
|
samples: samples.into(),
|
||||||
envelopes: &envelopes,
|
envelopes: envelopes.into(),
|
||||||
pattern_data: &pattern,
|
patterns: Cow::from(vec![Pattern {
|
||||||
patterns: &[Pattern {
|
|
||||||
length: pattern.len() / resulting_num_channels,
|
length: pattern.len() / resulting_num_channels,
|
||||||
start_position: 0,
|
start_position: 0,
|
||||||
}],
|
}]),
|
||||||
patterns_to_play: &[0],
|
pattern_data: pattern.into(),
|
||||||
|
patterns_to_play: Cow::from(vec![0]),
|
||||||
num_channels: resulting_num_channels,
|
num_channels: resulting_num_channels,
|
||||||
frames_per_tick: Num::from_f64(frames_per_tick),
|
frames_per_tick: Num::from_f64(frames_per_tick),
|
||||||
ticks_per_step: 1,
|
ticks_per_step: 1,
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
use agb_fixnum::Num;
|
use agb_fixnum::Num;
|
||||||
|
use alloc::borrow::Cow;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Track<'a> {
|
pub struct Track {
|
||||||
pub samples: &'a [Sample<'a>],
|
pub samples: Cow<'static, [Sample]>,
|
||||||
pub envelopes: &'a [Envelope<'a>],
|
pub envelopes: Cow<'static, [Envelope]>,
|
||||||
pub pattern_data: &'a [PatternSlot],
|
pub pattern_data: Cow<'static, [PatternSlot]>,
|
||||||
pub patterns: &'a [Pattern],
|
pub patterns: Cow<'static, [Pattern]>,
|
||||||
pub patterns_to_play: &'a [usize],
|
pub patterns_to_play: Cow<'static, [usize]>,
|
||||||
|
|
||||||
pub num_channels: usize,
|
pub num_channels: usize,
|
||||||
pub frames_per_tick: Num<u32, 8>,
|
pub frames_per_tick: Num<u32, 8>,
|
||||||
|
@ -16,9 +19,9 @@ pub struct Track<'a> {
|
||||||
pub repeat: usize,
|
pub repeat: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Sample<'a> {
|
pub struct Sample {
|
||||||
pub data: &'a [u8],
|
pub data: Cow<'static, [u8]>,
|
||||||
pub should_loop: bool,
|
pub should_loop: bool,
|
||||||
pub restart_point: u32,
|
pub restart_point: u32,
|
||||||
pub volume: Num<i16, 8>,
|
pub volume: Num<i16, 8>,
|
||||||
|
@ -26,7 +29,7 @@ pub struct Sample<'a> {
|
||||||
pub fadeout: Num<i32, 8>,
|
pub fadeout: Num<i32, 8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Pattern {
|
pub struct Pattern {
|
||||||
pub length: usize,
|
pub length: usize,
|
||||||
pub start_position: usize,
|
pub start_position: usize,
|
||||||
|
@ -40,9 +43,9 @@ pub struct PatternSlot {
|
||||||
pub effect2: PatternEffect,
|
pub effect2: PatternEffect,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Envelope<'a> {
|
pub struct Envelope {
|
||||||
pub amount: &'a [Num<i16, 8>],
|
pub amount: Cow<'static, [Num<i16, 8>]>,
|
||||||
pub sustain: Option<usize>,
|
pub sustain: Option<usize>,
|
||||||
pub loop_start: Option<usize>,
|
pub loop_start: Option<usize>,
|
||||||
pub loop_end: Option<usize>,
|
pub loop_end: Option<usize>,
|
||||||
|
@ -75,7 +78,7 @@ pub enum PatternEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "quote")]
|
#[cfg(feature = "quote")]
|
||||||
impl<'a> quote::ToTokens for Track<'a> {
|
impl quote::ToTokens for Track {
|
||||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||||
use quote::{quote, TokenStreamExt};
|
use quote::{quote, TokenStreamExt};
|
||||||
|
|
||||||
|
@ -95,20 +98,24 @@ impl<'a> quote::ToTokens for Track<'a> {
|
||||||
|
|
||||||
tokens.append_all(quote! {
|
tokens.append_all(quote! {
|
||||||
{
|
{
|
||||||
static SAMPLES: &[agb_tracker::__private::agb_tracker_interop::Sample<'static>] = &[#(#samples),*];
|
use alloc::borrow::Cow;
|
||||||
static PATTERN_DATA: &[agb_tracker::__private::agb_tracker_interop::PatternSlot] = &[#(#pattern_data),*];
|
use agb_tracker::__private::agb_tracker_interop::*;
|
||||||
static PATTERNS: &[agb_tracker::__private::agb_tracker_interop::Pattern] = &[#(#patterns),*];
|
use agb_tracker::__private::Num;
|
||||||
|
|
||||||
|
static SAMPLES: &[Sample] = &[#(#samples),*];
|
||||||
|
static PATTERN_DATA: &[PatternSlot] = &[#(#pattern_data),*];
|
||||||
|
static PATTERNS: &[Pattern] = &[#(#patterns),*];
|
||||||
static PATTERNS_TO_PLAY: &[usize] = &[#(#patterns_to_play),*];
|
static PATTERNS_TO_PLAY: &[usize] = &[#(#patterns_to_play),*];
|
||||||
static ENVELOPES: &[agb_tracker::__private::agb_tracker_interop::Envelope<'static>] = &[#(#envelopes),*];
|
static ENVELOPES: &[Envelope] = &[#(#envelopes),*];
|
||||||
|
|
||||||
agb_tracker::Track {
|
agb_tracker::Track {
|
||||||
samples: SAMPLES,
|
samples: Cow::Borrowed(SAMPLES),
|
||||||
envelopes: ENVELOPES,
|
envelopes: Cow::Borrowed(ENVELOPES),
|
||||||
pattern_data: PATTERN_DATA,
|
pattern_data: Cow::Borrowed(PATTERN_DATA),
|
||||||
patterns: PATTERNS,
|
patterns: Cow::Borrowed(PATTERNS),
|
||||||
patterns_to_play: PATTERNS_TO_PLAY,
|
patterns_to_play: Cow::Borrowed(PATTERNS_TO_PLAY),
|
||||||
|
|
||||||
frames_per_tick: agb_tracker::__private::Num::from_raw(#frames_per_tick),
|
frames_per_tick: Num::from_raw(#frames_per_tick),
|
||||||
num_channels: #num_channels,
|
num_channels: #num_channels,
|
||||||
ticks_per_step: #ticks_per_step,
|
ticks_per_step: #ticks_per_step,
|
||||||
repeat: #repeat,
|
repeat: #repeat,
|
||||||
|
@ -119,7 +126,7 @@ impl<'a> quote::ToTokens for Track<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "quote")]
|
#[cfg(feature = "quote")]
|
||||||
impl quote::ToTokens for Envelope<'_> {
|
impl quote::ToTokens for Envelope {
|
||||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||||
use quote::{quote, TokenStreamExt};
|
use quote::{quote, TokenStreamExt};
|
||||||
|
|
||||||
|
@ -153,7 +160,7 @@ impl quote::ToTokens for Envelope<'_> {
|
||||||
static AMOUNTS: &[agb_tracker::__private::Num<i16, 8>] = &[#(#amount),*];
|
static AMOUNTS: &[agb_tracker::__private::Num<i16, 8>] = &[#(#amount),*];
|
||||||
|
|
||||||
agb_tracker::__private::agb_tracker_interop::Envelope {
|
agb_tracker::__private::agb_tracker_interop::Envelope {
|
||||||
amount: AMOUNTS,
|
amount: Cow::Borrowed(AMOUNTS),
|
||||||
sustain: #sustain,
|
sustain: #sustain,
|
||||||
loop_start: #loop_start,
|
loop_start: #loop_start,
|
||||||
loop_end: #loop_end,
|
loop_end: #loop_end,
|
||||||
|
@ -175,7 +182,7 @@ impl quote::ToTokens for ByteString<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "quote")]
|
#[cfg(feature = "quote")]
|
||||||
impl<'a> quote::ToTokens for Sample<'a> {
|
impl quote::ToTokens for Sample {
|
||||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||||
use quote::{quote, TokenStreamExt};
|
use quote::{quote, TokenStreamExt};
|
||||||
|
|
||||||
|
@ -204,7 +211,7 @@ impl<'a> quote::ToTokens for Sample<'a> {
|
||||||
|
|
||||||
static SAMPLE_DATA: &[u8] = &AlignmentWrapper(*#samples).0;
|
static SAMPLE_DATA: &[u8] = &AlignmentWrapper(*#samples).0;
|
||||||
agb_tracker::__private::agb_tracker_interop::Sample {
|
agb_tracker::__private::agb_tracker_interop::Sample {
|
||||||
data: SAMPLE_DATA,
|
data: Cow::Borrowed(SAMPLE_DATA),
|
||||||
should_loop: #should_loop,
|
should_loop: #should_loop,
|
||||||
restart_point: #restart_point,
|
restart_point: #restart_point,
|
||||||
volume: agb_tracker::__private::Num::from_raw(#volume),
|
volume: agb_tracker::__private::Num::from_raw(#volume),
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
use agb::sound::mixer::Frequency;
|
use agb::sound::mixer::Frequency;
|
||||||
use agb::Gba;
|
use agb::Gba;
|
||||||
use agb_tracker::{include_xm, Track, Tracker};
|
use agb_tracker::{include_xm, Track, Tracker};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
use agb::sound::mixer::Frequency;
|
use agb::sound::mixer::Frequency;
|
||||||
use agb::Gba;
|
use agb::Gba;
|
||||||
use agb_tracker::{include_xm, Track, Tracker};
|
use agb_tracker::{include_xm, Track, Tracker};
|
||||||
|
|
|
@ -95,7 +95,7 @@ pub use agb_tracker_interop::Track;
|
||||||
|
|
||||||
/// Stores the required state in order to play tracker music.
|
/// Stores the required state in order to play tracker music.
|
||||||
pub struct Tracker {
|
pub struct Tracker {
|
||||||
track: &'static Track<'static>,
|
track: &'static Track,
|
||||||
channels: Vec<TrackerChannel>,
|
channels: Vec<TrackerChannel>,
|
||||||
envelopes: Vec<Option<EnvelopeState>>,
|
envelopes: Vec<Option<EnvelopeState>>,
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ struct GlobalSettings {
|
||||||
|
|
||||||
impl Tracker {
|
impl Tracker {
|
||||||
/// Create a new tracker playing a specified track. See the [example](crate#example) for how to use the tracker.
|
/// Create a new tracker playing a specified track. See the [example](crate#example) for how to use the tracker.
|
||||||
pub fn new(track: &'static Track<'static>) -> Self {
|
pub fn new(track: &'static Track) -> Self {
|
||||||
let mut channels = Vec::new();
|
let mut channels = Vec::new();
|
||||||
channels.resize_with(track.num_channels, Default::default);
|
channels.resize_with(track.num_channels, Default::default);
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ impl TrackerChannel {
|
||||||
fn play_sound(
|
fn play_sound(
|
||||||
&mut self,
|
&mut self,
|
||||||
mixer: &mut Mixer<'_>,
|
mixer: &mut Mixer<'_>,
|
||||||
sample: &Sample<'static>,
|
sample: &Sample,
|
||||||
global_settings: &GlobalSettings,
|
global_settings: &GlobalSettings,
|
||||||
) {
|
) {
|
||||||
if let Some(channel) = self
|
if let Some(channel) = self
|
||||||
|
@ -303,7 +303,12 @@ impl TrackerChannel {
|
||||||
channel.stop();
|
channel.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_channel = SoundChannel::new(sample.data);
|
let mut new_channel = SoundChannel::new(match sample.data {
|
||||||
|
alloc::borrow::Cow::Borrowed(data) => data,
|
||||||
|
alloc::borrow::Cow::Owned(_) => {
|
||||||
|
unimplemented!("Must use borrowed COW data for tracker")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
new_channel.volume(
|
new_channel.volume(
|
||||||
(sample.volume.change_base() * global_settings.volume)
|
(sample.volume.change_base() * global_settings.volume)
|
||||||
|
@ -482,7 +487,7 @@ impl TrackerChannel {
|
||||||
&mut self,
|
&mut self,
|
||||||
mixer: &mut Mixer<'_>,
|
mixer: &mut Mixer<'_>,
|
||||||
envelope_state: &EnvelopeState,
|
envelope_state: &EnvelopeState,
|
||||||
envelope: &agb_tracker_interop::Envelope<'_>,
|
envelope: &agb_tracker_interop::Envelope,
|
||||||
global_settings: &GlobalSettings,
|
global_settings: &GlobalSettings,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(channel) = self
|
if let Some(channel) = self
|
||||||
|
|
|
@ -13,7 +13,7 @@ proc-macro2 = "1"
|
||||||
quote = "1"
|
quote = "1"
|
||||||
syn = "2"
|
syn = "2"
|
||||||
|
|
||||||
agb_tracker_interop = { version = "0.20.5", path = "../agb-tracker-interop" }
|
agb_tracker_interop = { version = "0.20.5", path = "../agb-tracker-interop", default-features = false }
|
||||||
agb_fixnum = { version = "0.20.5", path = "../../agb-fixnum" }
|
agb_fixnum = { version = "0.20.5", path = "../../agb-fixnum" }
|
||||||
|
|
||||||
xmrs = { version = "0.6.1", features = ["std"] }
|
xmrs = { version = "0.6.1", features = ["std"] }
|
||||||
|
|
|
@ -1,51 +1,11 @@
|
||||||
use std::{collections::HashMap, error::Error, fs, path::Path};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use agb_tracker_interop::PatternEffect;
|
|
||||||
use proc_macro2::TokenStream;
|
|
||||||
use proc_macro_error::abort;
|
|
||||||
|
|
||||||
use quote::quote;
|
|
||||||
use syn::LitStr;
|
|
||||||
|
|
||||||
use agb_fixnum::Num;
|
use agb_fixnum::Num;
|
||||||
|
use agb_tracker_interop::PatternEffect;
|
||||||
|
|
||||||
use xmrs::{prelude::*, xm::xmmodule::XmModule};
|
use xmrs::prelude::*;
|
||||||
|
|
||||||
pub fn agb_xm_core(args: TokenStream) -> TokenStream {
|
pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
|
||||||
let input = match syn::parse::<LitStr>(args.into()) {
|
|
||||||
Ok(input) => input,
|
|
||||||
Err(err) => return err.to_compile_error(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let filename = input.value();
|
|
||||||
|
|
||||||
let root = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get cargo manifest dir");
|
|
||||||
let path = Path::new(&root).join(&*filename);
|
|
||||||
|
|
||||||
let include_path = path.to_string_lossy();
|
|
||||||
|
|
||||||
let module = match load_module_from_file(&path) {
|
|
||||||
Ok(track) => track,
|
|
||||||
Err(e) => abort!(input, e),
|
|
||||||
};
|
|
||||||
|
|
||||||
let parsed = parse_module(&module);
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
{
|
|
||||||
const _: &[u8] = include_bytes!(#include_path);
|
|
||||||
|
|
||||||
#parsed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_module_from_file(xm_path: &Path) -> Result<Module, Box<dyn Error>> {
|
|
||||||
let file_content = fs::read(xm_path)?;
|
|
||||||
Ok(XmModule::load(&file_content)?.to_module())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_module(module: &Module) -> TokenStream {
|
|
||||||
let instruments = &module.instrument;
|
let instruments = &module.instrument;
|
||||||
let mut instruments_map = HashMap::new();
|
let mut instruments_map = HashMap::new();
|
||||||
|
|
||||||
|
@ -414,7 +374,7 @@ pub fn parse_module(module: &Module) -> TokenStream {
|
||||||
let samples: Vec<_> = samples
|
let samples: Vec<_> = samples
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sample| agb_tracker_interop::Sample {
|
.map(|sample| agb_tracker_interop::Sample {
|
||||||
data: &sample.data,
|
data: sample.data.clone().into(),
|
||||||
should_loop: sample.should_loop,
|
should_loop: sample.should_loop,
|
||||||
restart_point: sample.restart_point,
|
restart_point: sample.restart_point,
|
||||||
volume: sample.volume,
|
volume: sample.volume,
|
||||||
|
@ -432,7 +392,7 @@ pub fn parse_module(module: &Module) -> TokenStream {
|
||||||
let envelopes = envelopes
|
let envelopes = envelopes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|envelope| agb_tracker_interop::Envelope {
|
.map(|envelope| agb_tracker_interop::Envelope {
|
||||||
amount: &envelope.amounts,
|
amount: envelope.amounts.clone().into(),
|
||||||
sustain: envelope.sustain,
|
sustain: envelope.sustain,
|
||||||
loop_start: envelope.loop_start,
|
loop_start: envelope.loop_start,
|
||||||
loop_end: envelope.loop_end,
|
loop_end: envelope.loop_end,
|
||||||
|
@ -442,20 +402,18 @@ pub fn parse_module(module: &Module) -> TokenStream {
|
||||||
let frames_per_tick = bpm_to_frames_per_tick(module.default_bpm as u32);
|
let frames_per_tick = bpm_to_frames_per_tick(module.default_bpm as u32);
|
||||||
let ticks_per_step = module.default_tempo;
|
let ticks_per_step = module.default_tempo;
|
||||||
|
|
||||||
let interop = agb_tracker_interop::Track {
|
agb_tracker_interop::Track {
|
||||||
samples: &samples,
|
samples: samples.into(),
|
||||||
pattern_data: &pattern_data,
|
pattern_data: pattern_data.into(),
|
||||||
patterns: &patterns,
|
patterns: patterns.into(),
|
||||||
num_channels: module.get_num_channels(),
|
num_channels: module.get_num_channels(),
|
||||||
patterns_to_play: &patterns_to_play,
|
patterns_to_play: patterns_to_play.into(),
|
||||||
envelopes: &envelopes,
|
envelopes: envelopes.into(),
|
||||||
|
|
||||||
frames_per_tick,
|
frames_per_tick,
|
||||||
ticks_per_step: ticks_per_step.into(),
|
ticks_per_step: ticks_per_step.into(),
|
||||||
repeat: module.restart_position as usize,
|
repeat: module.restart_position as usize,
|
||||||
};
|
}
|
||||||
|
|
||||||
quote!(#interop)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bpm_to_frames_per_tick(bpm: u32) -> Num<u32, 8> {
|
fn bpm_to_frames_per_tick(bpm: u32) -> Num<u32, 8> {
|
||||||
|
|
|
@ -14,3 +14,8 @@ proc-macro = true
|
||||||
agb_xm_core = { version = "0.20.5", path = "../agb-xm-core" }
|
agb_xm_core = { version = "0.20.5", path = "../agb-xm-core" }
|
||||||
proc-macro-error = "1"
|
proc-macro-error = "1"
|
||||||
proc-macro2 = "1"
|
proc-macro2 = "1"
|
||||||
|
|
||||||
|
quote = "1"
|
||||||
|
syn = "2"
|
||||||
|
|
||||||
|
xmrs = "0.6"
|
||||||
|
|
|
@ -1,8 +1,49 @@
|
||||||
|
use std::{error::Error, fs, path::Path};
|
||||||
|
|
||||||
|
use agb_xm_core::parse_module;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro_error::proc_macro_error;
|
use proc_macro_error::{abort, proc_macro_error};
|
||||||
|
use quote::quote;
|
||||||
|
use syn::LitStr;
|
||||||
|
use xmrs::{module::Module, xm::xmmodule::XmModule};
|
||||||
|
|
||||||
#[proc_macro_error]
|
#[proc_macro_error]
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn include_xm(args: TokenStream) -> TokenStream {
|
pub fn include_xm(args: TokenStream) -> TokenStream {
|
||||||
agb_xm_core::agb_xm_core(args.into()).into()
|
agb_xm_core(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn agb_xm_core(args: TokenStream) -> TokenStream {
|
||||||
|
let input = match syn::parse::<LitStr>(args) {
|
||||||
|
Ok(input) => input,
|
||||||
|
Err(err) => return err.to_compile_error().into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let filename = input.value();
|
||||||
|
|
||||||
|
let root = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get cargo manifest dir");
|
||||||
|
let path = Path::new(&root).join(&*filename);
|
||||||
|
|
||||||
|
let include_path = path.to_string_lossy();
|
||||||
|
|
||||||
|
let module = match load_module_from_file(&path) {
|
||||||
|
Ok(track) => track,
|
||||||
|
Err(e) => abort!(input, e),
|
||||||
|
};
|
||||||
|
|
||||||
|
let parsed = parse_module(&module);
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
{
|
||||||
|
const _: &[u8] = include_bytes!(#include_path);
|
||||||
|
|
||||||
|
#parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_module_from_file(xm_path: &Path) -> Result<Module, Box<dyn Error>> {
|
||||||
|
let file_content = fs::read(xm_path)?;
|
||||||
|
Ok(XmModule::load(&file_content)?.to_module())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue