use crate::error::{GpResult, ToPrimitiveGp};
use crate::{
io::primitive::*,
model::{enums::*, song::*, track::*},
};
#[derive(Debug, Clone)]
pub struct RseEqualizer {
pub knobs: Vec<f32>,
pub gain: f32,
}
impl Default for RseEqualizer {
fn default() -> Self {
RseEqualizer {
knobs: Vec::with_capacity(10),
gain: 0.0,
}
}
}
#[derive(Debug, Clone)]
pub struct RseMasterEffect {
pub volume: f32,
pub reverb: f32,
pub equalizer: RseEqualizer,
}
impl Default for RseMasterEffect {
fn default() -> Self {
RseMasterEffect {
volume: 0.0,
reverb: 0.0,
equalizer: RseEqualizer {
knobs: vec![0.0; 10],
..Default::default()
},
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RseInstrument {
pub instrument: i16,
pub unknown: i16,
pub sound_bank: i16,
pub effect_number: i16,
pub effect_category: String,
pub effect: String,
}
impl Default for RseInstrument {
fn default() -> Self {
RseInstrument {
instrument: -1,
unknown: -1,
sound_bank: -1,
effect_number: -1,
effect_category: String::new(),
effect: String::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct TrackRse {
pub instrument: RseInstrument,
pub equalizer: RseEqualizer,
pub humanize: u8,
pub auto_accentuation: Accentuation,
}
impl Default for TrackRse {
fn default() -> Self {
TrackRse {
instrument: RseInstrument::default(),
humanize: 0,
auto_accentuation: Accentuation::None,
equalizer: RseEqualizer {
knobs: vec![0.0; 3],
..Default::default()
},
}
}
}
pub trait SongRseOps {
fn read_rse_master_effect(&self, data: &[u8], seek: &mut usize) -> GpResult<RseMasterEffect>;
fn read_rse_equalizer(
&self,
data: &[u8],
seek: &mut usize,
knobs: u8,
) -> GpResult<RseEqualizer>;
fn unpack_volume_value(&self, value: i8) -> f32;
fn read_track_rse(&mut self, data: &[u8], seek: &mut usize, track: &mut Track) -> GpResult<()>;
fn read_rse_instrument(&mut self, data: &[u8], seek: &mut usize) -> GpResult<RseInstrument>;
fn read_rse_instrument_effect(
&mut self,
data: &[u8],
seek: &mut usize,
instrument: &mut RseInstrument,
) -> GpResult<()>;
fn write_rse_master_effect(&self, data: &mut Vec<u8>);
fn write_equalizer(&self, data: &mut Vec<u8>, equalizer: &RseEqualizer);
fn pack_volume_value(&self, value: f32) -> i8;
fn write_master_reverb(&self, data: &mut Vec<u8>);
fn write_track_rse(&self, data: &mut Vec<u8>, rse: &TrackRse, version: &(u8, u8, u8));
fn write_rse_instrument(
&self,
data: &mut Vec<u8>,
instrument: &RseInstrument,
version: &(u8, u8, u8),
);
fn write_rse_instrument_effect(&self, data: &mut Vec<u8>, instrument: &RseInstrument);
}
impl SongRseOps for Song {
fn read_rse_master_effect(&self, data: &[u8], seek: &mut usize) -> GpResult<RseMasterEffect> {
let mut me = RseMasterEffect::default();
if self.version.number > (5, 0, 0) {
me.volume = read_int(data, seek)?.to_f32_gp("rse master effect volume")?;
read_int(data, seek)?; me.equalizer = self.read_rse_equalizer(data, seek, 11)?;
}
Ok(me)
}
fn read_rse_equalizer(
&self,
data: &[u8],
seek: &mut usize,
knobs: u8,
) -> GpResult<RseEqualizer> {
let mut e = RseEqualizer::default();
for _ in 0..knobs {
e.knobs
.push(self.unpack_volume_value(read_signed_byte(data, seek)?));
} Ok(e) }
fn unpack_volume_value(&self, value: i8) -> f32 {
-(value as f32) / 10.0
}
fn read_track_rse(&mut self, data: &[u8], seek: &mut usize, track: &mut Track) -> GpResult<()> {
track.rse.humanize = read_byte(data, seek)?;
*seek += 12; *seek += 12; track.rse.instrument = self.read_rse_instrument(data, seek)?;
if self.version.number > (5, 0, 0) {
track.rse.equalizer = self.read_rse_equalizer(data, seek, 4)?;
self.read_rse_instrument_effect(data, seek, &mut track.rse.instrument)?;
}
Ok(())
}
fn read_rse_instrument(&mut self, data: &[u8], seek: &mut usize) -> GpResult<RseInstrument> {
let mut instrument = RseInstrument {
instrument: read_int(data, seek)?.to_i16_gp("rse instrument number")?,
..Default::default()
};
instrument.unknown = read_int(data, seek)?.to_i16_gp("rse instrument unknown")?; instrument.sound_bank = read_int(data, seek)?.to_i16_gp("rse instrument sound bank")?;
if self.version.number == (5, 0, 0) {
instrument.effect_number = read_short(data, seek)?;
*seek += 1;
} else {
instrument.effect_number =
read_int(data, seek)?.to_i16_gp("rse instrument effect number")?;
}
Ok(instrument)
}
fn read_rse_instrument_effect(
&mut self,
data: &[u8],
seek: &mut usize,
instrument: &mut RseInstrument,
) -> GpResult<()> {
if self.version.number > (5, 0, 0) {
instrument.effect = read_int_byte_size_string(data, seek)?;
instrument.effect_category = read_int_byte_size_string(data, seek)?;
}
Ok(())
}
fn write_rse_master_effect(&self, data: &mut Vec<u8>) {
write_i32(
data,
if self.master_effect.volume == 0.0 {
100
} else {
self.master_effect.volume.ceil() as i32
},
);
write_i32(data, 0); self.write_equalizer(data, &self.master_effect.equalizer);
}
fn write_equalizer(&self, data: &mut Vec<u8>, equalizer: &RseEqualizer) {
for i in 0..equalizer.knobs.len() {
write_signed_byte(data, self.pack_volume_value(equalizer.knobs[i]));
}
}
fn pack_volume_value(&self, value: f32) -> i8 {
(-value * 10f32).round() as i8 }
fn write_master_reverb(&self, data: &mut Vec<u8>) {
write_i32(data, self.master_effect.reverb as i32);
}
fn write_track_rse(&self, data: &mut Vec<u8>, rse: &TrackRse, version: &(u8, u8, u8)) {
write_byte(data, rse.humanize);
write_i32(data, 0);
write_i32(data, 0);
write_i32(data, 100);
write_placeholder_default(data, 12);
self.write_rse_instrument(data, &rse.instrument, version);
if version > &(5, 0, 0) {
self.write_equalizer(data, &rse.equalizer);
self.write_rse_instrument_effect(data, &rse.instrument);
}
}
fn write_rse_instrument(
&self,
data: &mut Vec<u8>,
instrument: &RseInstrument,
version: &(u8, u8, u8),
) {
write_i32(data, instrument.instrument as i32);
write_i32(data, instrument.unknown as i32);
write_i32(data, instrument.sound_bank as i32);
if version == &(5, 0, 0) {
write_i16(data, instrument.effect_number);
write_placeholder_default(data, 1);
} else {
write_i32(data, instrument.effect_number as i32);
}
}
fn write_rse_instrument_effect(&self, data: &mut Vec<u8>, instrument: &RseInstrument) {
write_int_byte_size_string(data, &instrument.effect);
write_int_byte_size_string(data, &instrument.effect_category);
}
}