Skip to content

Commit

Permalink
Add data for PTV envelope & support PTV release in rust impl
Browse files Browse the repository at this point in the history
  • Loading branch information
PieKing1215 committed Feb 27, 2024
1 parent e466c38 commit b82ce4e
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 36 deletions.
16 changes: 16 additions & 0 deletions src/pxtone/interface/woice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,27 @@ pub enum PTVWaveType<'a, C: PTVCoordinateWave, O: PTVOvertoneWave> {
Overtone(&'a O),
}

pub trait PTVEnvelope {
type EnvelopePoint: PTNEnvelopePoint;

fn fps(&self) -> u32;

fn head_num(&self) -> u32;

fn body_num(&self) -> u32;

fn tail_num(&self) -> u32;

fn points(&self) -> Vec<&Self::EnvelopePoint>;
}

pub trait VoicePTV: Voice {
type CoordinateWave: PTVCoordinateWave;
type OvertoneWave: PTVOvertoneWave;
type Envelope: PTVEnvelope;

fn wave(&self) -> PTVWaveType<Self::CoordinateWave, Self::OvertoneWave>;
fn envelope(&self) -> &Self::Envelope;
}

#[repr(u8)]
Expand Down
2 changes: 2 additions & 0 deletions src/pxtone/og_impl/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ impl Error {
}

pub fn from_raw(value: pxtnERR) -> Result<(), Error> {
// iirc this cast was needed on linux because pxtnERR was compiled as u32 (?)
#[allow(clippy::unnecessary_cast)]
Self::from_i32(value as i32).map_or(Ok(()), Err)
}
}
Expand Down
40 changes: 34 additions & 6 deletions src/pxtone/og_impl/woice.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
use std::{ffi::CString, slice, io::Read};

use pxtone_sys::{
pxNOISEDESIGN_OSCILLATOR, pxNOISEDESIGN_UNIT, pxtnPOINT, pxtnVOICEUNIT, pxtnVOICEWAVE,
pxtnWoice, pxtnDescriptor, pxtnWOICETYPE_pxtnWOICE_PCM, pxtnWOICETYPE, pxtnWOICETYPE_pxtnWOICE_PTN, pxtnWOICETYPE_pxtnWOICE_PTV, pxtnWOICETYPE_pxtnWOICE_OGGV,
pxNOISEDESIGN_OSCILLATOR, pxNOISEDESIGN_UNIT, pxtnDescriptor, pxtnPOINT, pxtnVOICEENVELOPE, pxtnVOICEUNIT, pxtnVOICEWAVE, pxtnWOICETYPE, pxtnWOICETYPE_pxtnWOICE_OGGV, pxtnWOICETYPE_pxtnWOICE_PCM, pxtnWOICETYPE_pxtnWOICE_PTN, pxtnWOICETYPE_pxtnWOICE_PTV, pxtnWoice
};

use crate::{
interface::{
service::InvalidText,
woice::{
HasWoices, PTNEnvelopePoint, PTNOscillator, PTNUnit, PTNWaveType, PTVCoordinateWave,
PTVCoordinateWavePoint, PTVOvertoneWave, PTVOvertoneWaveTone, PTVWaveType, SingleVoice,
Voice, VoiceOGGV, VoicePCM, VoicePTN, VoicePTV, Woice, WoiceOGGV, WoicePCM, WoicePTN,
WoicePTV, WoiceType, WoiceTypeMut, WoiceTypeRef, Woices, WoicesMut,
HasWoices, PTNEnvelopePoint, PTNOscillator, PTNUnit, PTNWaveType, PTVCoordinateWave, PTVCoordinateWavePoint, PTVEnvelope, PTVOvertoneWave, PTVOvertoneWaveTone, PTVWaveType, SingleVoice, Voice, VoiceOGGV, VoicePCM, VoicePTN, VoicePTV, Woice, WoiceOGGV, WoicePCM, WoicePTN, WoicePTV, WoiceType, WoiceTypeMut, WoiceTypeRef, Woices, WoicesMut
},
},
pxtone::util::{BoxOrMut, BoxOrRef},
Expand Down Expand Up @@ -223,9 +219,37 @@ impl PTVOvertoneWave for pxtnVOICEWAVE {
}
}

impl PTVEnvelope for pxtnVOICEENVELOPE {
type EnvelopePoint = pxtnPOINT;

fn fps(&self) -> u32 {
self.fps as _
}

fn head_num(&self) -> u32 {
self.head_num as _
}

fn body_num(&self) -> u32 {
self.body_num as _
}

fn tail_num(&self) -> u32 {
self.tail_num as _
}

fn points(&self) -> Vec<&Self::EnvelopePoint> {
let num = self.head_num + self.body_num + self.tail_num;
let slice = unsafe { slice::from_raw_parts(self.points, num as usize) };

slice.iter().collect()
}
}

impl VoicePTV for pxtnVOICEUNIT {
type CoordinateWave = pxtnVOICEWAVE;
type OvertoneWave = pxtnVOICEWAVE;
type Envelope = pxtnVOICEENVELOPE;

fn wave(&self) -> PTVWaveType<Self::CoordinateWave, Self::OvertoneWave> {
if self.type_ == pxtone_sys::pxtnVOICETYPE_pxtnVOICE_Coodinate {
Expand All @@ -234,6 +258,10 @@ impl VoicePTV for pxtnVOICEUNIT {
PTVWaveType::Overtone(&self.wave)
}
}

fn envelope(&self) -> &Self::Envelope {
todo!()
}
}

impl PTNEnvelopePoint for pxtnPOINT {
Expand Down
63 changes: 42 additions & 21 deletions src/pxtone/rust_impl/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ use crate::{
rust_impl::{
unit::RPxToneUnit,
woice::{
RPxTonePTVCoordinatePoint, RPxTonePTVCoordinateWave, RPxTonePTVOvertoneWave,
RPxTonePTVOvertoneWaveTone, RPxTonePTVWaveType, RPxToneVoicePCM, RPxToneVoicePCMError,
RPxToneVoicePTV, RPxToneWoice, RPxToneWoicePCM, RPxToneWoiceType,
RPXTonePTVEnvelope, RPxTonePTNEnvelopePoint, RPxTonePTVCoordinatePoint, RPxTonePTVCoordinateWave, RPxTonePTVOvertoneWave, RPxTonePTVOvertoneWaveTone, RPxTonePTVWaveType, RPxToneVoicePCM, RPxToneVoicePCMError, RPxToneVoicePTV, RPxToneWoice, RPxToneWoicePCM, RPxToneWoiceType
},
},
};
Expand Down Expand Up @@ -336,34 +334,57 @@ impl PxToneServiceIO for RPxTone {
_ => panic!("Invalid wave type"),
};

let voice = RPxToneVoicePTV::new(
basic_key as _,
volume as _,
pan as _,
f32::from_le_bytes(tuning.to_le_bytes()),
wave,
);

if data_flags & 0x2 != 0 {
// TODO: envelope

let _fps = v_r(&mut c).unwrap();
#[allow(clippy::if_not_else)]
let envelope = if data_flags & 0x2 != 0 {
let fps = v_r(&mut c).unwrap();
let head_num = v_r(&mut c).unwrap();
let body_num = v_r(&mut c).unwrap();
let tail_num = v_r(&mut c).unwrap();

println!("{_fps}, {head_num}, {body_num}, {tail_num}");
println!("{fps}, {head_num}, {body_num}, {tail_num}");

assert_eq!(body_num, 0);
assert_eq!(tail_num, 1);

let num = head_num + body_num + tail_num;

(0..num).map(|_| {
let _x = v_r(&mut c).unwrap();
let _y = v_r(&mut c).unwrap();
}).for_each(drop);
}
let points: Vec<_> = (0..num).map(|_| {
let x = v_r(&mut c).unwrap();
let y = v_r(&mut c).unwrap();

RPxTonePTNEnvelopePoint {
x,
y: y as _,
}
}).collect();

println!("points = {points:?}");
let env_release = if tail_num > 0 {
points[head_num as usize].x * 44100 / fps
} else {
0
};
println!("env_release = {env_release}");

RPXTonePTVEnvelope {
fps,
head_num,
body_num,
tail_num,
points,
}
} else {
RPXTonePTVEnvelope::default()
};

let voice = RPxToneVoicePTV::new(
basic_key as _,
volume as _,
pan as _,
f32::from_le_bytes(tuning.to_le_bytes()),
wave,
envelope
);

return Some(voice);
}
Expand Down
49 changes: 44 additions & 5 deletions src/pxtone/rust_impl/moo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
},
moo::{AsMooRef, Moo},
service::PxTone,
woice::{VoicePCM, Woice, WoiceType},
woice::{VoicePCM, VoicePTV, Woice, WoiceType},
},
util::{BoxOrMut, ZeroToOneF32},
};
Expand Down Expand Up @@ -213,10 +213,6 @@ impl<'a> Moo<'a> for RPxToneMoo<'a> {
#[allow(clippy::for_kv_map)]
for (_unit, data) in &mut self.unit_data {
if let Some(on) = &mut data.on {
if clock_ticks > (on.start + on.length) as f32 {
data.on = None;
continue;
}

// let on_ticks = clock_ticks - on.start as f32;
// let on_secs = on_ticks / ticks_per_sec;
Expand Down Expand Up @@ -264,6 +260,12 @@ impl<'a> Moo<'a> for RPxToneMoo<'a> {
#[allow(clippy::single_match)]
match woice.woice_type() {
WoiceType::PCM(pcm) => {

if clock_ticks > (on.start + on.length) as f32 {
data.on = None;
continue;
}

for (ch, v) in v.iter_mut().enumerate() {
let mut val = pcm.voice.sample(cycle, ch as _);

Expand All @@ -281,6 +283,12 @@ impl<'a> Moo<'a> for RPxToneMoo<'a> {
}
},
WoiceType::OGGV(oggv) => {

if clock_ticks > (on.start + on.length) as f32 {
data.on = None;
continue;
}

for (ch, v) in v.iter_mut().enumerate() {
let mut val = oggv.voice.sample(cycle, ch as _);

Expand All @@ -298,7 +306,34 @@ impl<'a> Moo<'a> for RPxToneMoo<'a> {
}
},
WoiceType::PTV(ptv) => {

let max_env_release_samples = ptv.voices.iter().map(|v| {
if v.envelope.tail_num > 0 {
v.envelope.points[v.envelope.head_num as usize].x * self.sample_rate / v.envelope.fps
} else {
0
}
}).max().unwrap_or(0);

// samples / samples/sec * ticks/seconds = ticks
let max_env_release_ticks = (max_env_release_samples as f32 / self.sample_rate as f32 * ticks_per_sec) as u32;

if clock_ticks > (on.start + on.length + max_env_release_ticks) as f32 {
data.on = None;
continue;
}

for voice in &ptv.voices {

let env_release_samples = if voice.envelope.tail_num > 0 {
voice.envelope.points[voice.envelope.head_num as usize].x * self.sample_rate / voice.envelope.fps
} else {
0
};

// samples / samples/sec * ticks/seconds = ticks
let env_release_ticks = env_release_samples as f32 / self.sample_rate as f32 * ticks_per_sec;

for (ch, v) in v.iter_mut().enumerate() {
let mut val = voice.sample(cycle, ch as _);

Expand All @@ -309,6 +344,10 @@ impl<'a> Moo<'a> for RPxToneMoo<'a> {
val *= (cycle * 44100.0) / smooth_smps as f32;
}

if clock_ticks > (on.start + on.length) as f32 {
val *= (1.0 - (clock_ticks - (on.start + on.length) as f32) / env_release_ticks).clamp(0.0, 1.0);
}

*v += val
* *data.volume
* *data.velocity
Expand Down
47 changes: 43 additions & 4 deletions src/pxtone/rust_impl/woice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ use crate::{
interface::{
service::InvalidText,
woice::{
HasWoices, PTNEnvelopePoint, PTNOscillator, PTNUnit, PTNWaveType, PTVCoordinateWave,
PTVCoordinateWavePoint, PTVOvertoneWave, PTVOvertoneWaveTone, PTVWaveType, SingleVoice,
Voice, VoiceOGGV, VoicePCM, VoicePTN, VoicePTV, Woice, WoiceOGGV, WoicePCM, WoicePTN,
WoicePTV, WoiceTypeMut, WoiceTypeRef, Woices, WoicesMut,
HasWoices, PTNEnvelopePoint, PTNOscillator, PTNUnit, PTNWaveType, PTVCoordinateWave, PTVCoordinateWavePoint, PTVEnvelope, PTVOvertoneWave, PTVOvertoneWaveTone, PTVWaveType, SingleVoice, Voice, VoiceOGGV, VoicePCM, VoicePTN, VoicePTV, Woice, WoiceOGGV, WoicePCM, WoicePTN, WoicePTV, WoiceTypeMut, WoiceTypeRef, Woices, WoicesMut
},
},
util::{BoxOrMut, BoxOrRef},
Expand Down Expand Up @@ -233,6 +230,7 @@ pub struct RPxToneVoicePTV {
pub(crate) tuning: f32,

pub(crate) wave: RPxTonePTVWaveType,
pub(crate) envelope: RPXTonePTVEnvelope,

pub(crate) samples: Vec<f32>,
pub(crate) ratio_to_a: f32,
Expand All @@ -246,6 +244,7 @@ impl RPxToneVoicePTV {
pan: i32,
tuning: f32,
wave: RPxTonePTVWaveType,
envelope: RPXTonePTVEnvelope,
) -> Self {
let sample_num = 400;
let channels = 2;
Expand Down Expand Up @@ -279,6 +278,7 @@ impl RPxToneVoicePTV {
pan,
tuning,
wave,
envelope,
samples,
ratio_to_a,
}
Expand Down Expand Up @@ -327,13 +327,18 @@ impl Voice for RPxToneVoicePTV {
impl VoicePTV for RPxToneVoicePTV {
type CoordinateWave = RPxTonePTVCoordinateWave;
type OvertoneWave = RPxTonePTVOvertoneWave;
type Envelope = RPXTonePTVEnvelope;

fn wave(&self) -> PTVWaveType<Self::CoordinateWave, Self::OvertoneWave> {
match &self.wave {
RPxTonePTVWaveType::Coordinate(c) => PTVWaveType::Coordinate(c),
RPxTonePTVWaveType::Overtone(o) => PTVWaveType::Overtone(o),
}
}

fn envelope(&self) -> &Self::Envelope {
&self.envelope
}
}

impl VoicePCM for RPxToneVoicePTV {
Expand Down Expand Up @@ -476,6 +481,39 @@ impl PTVOvertoneWaveTone for RPxTonePTVOvertoneWaveTone {
}
}

#[derive(Default)]
pub struct RPXTonePTVEnvelope {
pub(crate) fps: u32,
pub(crate) head_num: u32,
pub(crate) body_num: u32,
pub(crate) tail_num: u32,
pub(crate) points: Vec<RPxTonePTNEnvelopePoint>,
}

impl PTVEnvelope for RPXTonePTVEnvelope {
type EnvelopePoint = RPxTonePTNEnvelopePoint;

fn fps(&self) -> u32 {
self.fps
}

fn head_num(&self) -> u32 {
self.head_num
}

fn body_num(&self) -> u32 {
self.body_num
}

fn tail_num(&self) -> u32 {
self.tail_num
}

fn points(&self) -> Vec<&Self::EnvelopePoint> {
self.points.iter().collect()
}
}

pub struct RPxToneWoicePTN {
pub(crate) voice: RPxToneVoicePTN,
}
Expand Down Expand Up @@ -626,6 +664,7 @@ impl PTNUnit for RPxTonePTNUnit {
}
}

#[derive(Debug)]
pub struct RPxTonePTNEnvelopePoint {
pub(crate) x: u32,
pub(crate) y: u8,
Expand Down

0 comments on commit b82ce4e

Please sign in to comment.