From 62ed54b5d6373b1b16363f7f7a6fded02c0cfcf6 Mon Sep 17 00:00:00 2001 From: MBMS <31241793+MyBlackMIDIScore@users.noreply.github.com> Date: Mon, 5 Aug 2024 08:19:05 +0000 Subject: [PATCH] SF2: Fix loop offsets + tuning (#81) --- soundfonts/src/sf2/preset.rs | 36 ++++++++++++--------- soundfonts/src/sf2/zone.rs | 61 +++++++++++++++++++----------------- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/soundfonts/src/sf2/preset.rs b/soundfonts/src/sf2/preset.rs index 801bc2f..ca927a6 100644 --- a/soundfonts/src/sf2/preset.rs +++ b/soundfonts/src/sf2/preset.rs @@ -76,22 +76,28 @@ impl Sf2ParsedPreset { .loop_mode .unwrap_or(subzone.loop_mode.unwrap_or(LoopMode::NoLoop)), loop_start: { - let v = (sample.loop_start as i32 - + subzone.loop_start_offset.unwrap_or(0) as i32) - as u32; + let offset = subzone.loop_start_offset.unwrap_or(0) as i32 + + (subzone.loop_start_offset_coarse.unwrap_or(0) as i32 + * 32768); + let v = (sample.loop_start as i32 + offset) as u32; convert_sample_index(v, sample.sample_rate, sample_rate) }, loop_end: { - let v = (sample.loop_end as i32 - + subzone.loop_end_offset.unwrap_or(0) as i32) - as u32; + let offset = subzone.loop_end_offset.unwrap_or(0) as i32 + + (subzone.loop_end_offset_coarse.unwrap_or(0) as i32 + * 32768); + let v = (sample.loop_end as i32 + offset) as u32; convert_sample_index(v, sample.sample_rate, sample_rate) }, - offset: convert_sample_index( - subzone.offset.unwrap_or(0) as u32, - sample.sample_rate, - sample_rate, - ), + offset: { + let zone_offset = subzone.offset.unwrap_or(0) as u32 + + subzone.offset_coarse.unwrap_or(0) as u32 * 32768; + convert_sample_index( + zone_offset, + sample.sample_rate, + sample_rate, + ) + }, cutoff: subzone.cutoff.map(|v| { 2f32.powf(v as f32 / 1200.0) * 8.176 @@ -100,11 +106,11 @@ impl Sf2ParsedPreset { resonance: zone.resonance.unwrap_or(subzone.resonance.unwrap_or(0)) as f32 / 10.0, - fine_tune: zone.fine_tune.unwrap_or(subzone.fine_tune.unwrap_or(0)) + fine_tune: zone.fine_tune.unwrap_or(0) + + subzone.fine_tune.unwrap_or(0) + sample.pitchadj as i16, - coarse_tune: zone - .coarse_tune - .unwrap_or(subzone.coarse_tune.unwrap_or(0)), + coarse_tune: zone.coarse_tune.unwrap_or(0) + + subzone.coarse_tune.unwrap_or(0), ampeg_envelope: AmpegEnvelopeParams { ampeg_start: 0.0, ampeg_delay: subzone.env_delay.unwrap_or(0.0) diff --git a/soundfonts/src/sf2/zone.rs b/soundfonts/src/sf2/zone.rs index af4ee64..fec7087 100644 --- a/soundfonts/src/sf2/zone.rs +++ b/soundfonts/src/sf2/zone.rs @@ -6,8 +6,11 @@ use std::ops::RangeInclusive; pub struct Sf2Zone { pub index: Option, pub offset: Option, + pub offset_coarse: Option, pub loop_start_offset: Option, + pub loop_start_offset_coarse: Option, pub loop_end_offset: Option, + pub loop_end_offset_coarse: Option, pub loop_mode: Option, pub cutoff: Option, pub resonance: Option, @@ -34,76 +37,78 @@ impl Sf2Zone { for (i, zone) in zones.iter().enumerate() { let mut region = global_region.clone(); - for r#gen in &zone.gen_list { - match r#gen.ty { - GeneratorType::StartAddrsOffset => { - region.offset = r#gen.amount.as_i16().copied() + for gen in &zone.gen_list { + match gen.ty { + GeneratorType::StartAddrsOffset => region.offset = gen.amount.as_i16().copied(), + GeneratorType::StartAddrsCoarseOffset => { + region.offset_coarse = gen.amount.as_i16().copied() } GeneratorType::StartloopAddrsOffset => { - region.loop_start_offset = r#gen.amount.as_i16().copied() + region.loop_start_offset = gen.amount.as_i16().copied() + } + GeneratorType::StartloopAddrsCoarseOffset => { + region.loop_start_offset_coarse = gen.amount.as_i16().copied() } GeneratorType::EndloopAddrsOffset => { - region.loop_end_offset = r#gen.amount.as_i16().copied() + region.loop_end_offset = gen.amount.as_i16().copied() } - GeneratorType::InitialFilterFc => { - region.cutoff = r#gen.amount.as_i16().copied() + GeneratorType::EndloopAddrsCoarseOffset => { + region.loop_end_offset_coarse = gen.amount.as_i16().copied() } + GeneratorType::InitialFilterFc => region.cutoff = gen.amount.as_i16().copied(), GeneratorType::InitialFilterQ => { - region.resonance = r#gen.amount.as_i16().copied() + region.resonance = gen.amount.as_i16().copied() } - GeneratorType::Pan => region.pan = r#gen.amount.as_i16().copied(), + GeneratorType::Pan => region.pan = gen.amount.as_i16().copied(), GeneratorType::DelayVolEnv => { region.env_delay = - r#gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) + gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) } GeneratorType::AttackVolEnv => { region.env_attack = - r#gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) + gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) } GeneratorType::HoldVolEnv => { - region.env_hold = - r#gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) + region.env_hold = gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) } GeneratorType::DecayVolEnv => { region.env_decay = - r#gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) + gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) } GeneratorType::SustainVolEnv => { - region.env_sustain = r#gen + region.env_sustain = gen .amount .as_i16() .map(|v| 10f32.powf(-1.0 * *v as f32 / 200.0) * 100.0) } GeneratorType::ReleaseVolEnv => { region.env_release = - r#gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) + gen.amount.as_i16().map(|v| 2f32.powf(*v as f32 / 1200.0)) } GeneratorType::KeyRange => { - let range = r#gen.amount.as_range().copied(); + let range = gen.amount.as_range().copied(); region.keyrange = range.map(|v| v.low..=v.high) } GeneratorType::VelRange => { - let range = r#gen.amount.as_range().copied(); + let range = gen.amount.as_range().copied(); region.velrange = range.map(|v| v.low..=v.high) } GeneratorType::InitialAttenuation => { - region.attenuation = r#gen.amount.as_i16().copied() - } - GeneratorType::CoarseTune => { - region.coarse_tune = r#gen.amount.as_i16().copied() + region.attenuation = gen.amount.as_i16().copied() } - GeneratorType::FineTune => region.fine_tune = r#gen.amount.as_i16().copied(), - GeneratorType::SampleID => region.index = r#gen.amount.as_u16().copied(), - GeneratorType::Instrument => region.index = r#gen.amount.as_u16().copied(), + GeneratorType::CoarseTune => region.coarse_tune = gen.amount.as_i16().copied(), + GeneratorType::FineTune => region.fine_tune = gen.amount.as_i16().copied(), + GeneratorType::SampleID => region.index = gen.amount.as_u16().copied(), + GeneratorType::Instrument => region.index = gen.amount.as_u16().copied(), GeneratorType::SampleModes => { - region.loop_mode = r#gen.amount.as_i16().map(|v| match v { + region.loop_mode = gen.amount.as_i16().map(|v| match v { 1 => LoopMode::LoopContinuous, 3 => LoopMode::LoopSustain, _ => LoopMode::NoLoop, }) } GeneratorType::OverridingRootKey => { - region.root_override = r#gen.amount.as_i16().copied() + region.root_override = gen.amount.as_i16().copied() } _ => {} }