Skip to content

Commit

Permalink
Port voice related methods of TFruityPlug (#78)
Browse files Browse the repository at this point in the history
- add voice module
- add VoiceHandler
- restructure plugin module
- remove hybrid generator stuff
  • Loading branch information
ales-tsurko authored May 2, 2020
1 parent 333a5c6 commit 73d8f1d
Show file tree
Hide file tree
Showing 7 changed files with 513 additions and 265 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/target
Cargo.lock
debug.sh
debug.flp
*.flp
92 changes: 75 additions & 17 deletions examples/simple.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
#[cfg(unix)]
use std::fs::OpenOptions;
use std::io::{self, Read};
Expand All @@ -13,18 +14,20 @@ use simple_logging;
use simplelog::{ConfigBuilder, WriteLogger};

use fpsdk::host::{Event, GetName, Host, HostMessage};
use fpsdk::plugin::{Info, InfoBuilder, Plugin, PluginTag, StateReader, StateWriter};
use fpsdk::{create_plugin, AsRawPtr, MidiMessage, ProcessParamFlags, ValuePtr};
use fpsdk::plugin::{Info, InfoBuilder, Plugin, StateReader, StateWriter};
use fpsdk::voice::{self, Voice, VoiceHandler};
use fpsdk::{create_plugin, AsRawPtr, MidiMessage, ProcessParamFlags, Tag, ValuePtr};

static ONCE: Once = Once::new();
const LOG_PATH: &str = "simple.log";

#[derive(Debug)]
struct Test {
struct Simple {
host: Host,
tag: PluginTag,
tag: Tag,
param_names: Vec<String>,
state: State,
voice_handler: SimpleVoiceHandler,
}

#[derive(Debug, Default, Deserialize, Serialize)]
Expand All @@ -34,8 +37,8 @@ struct State {
_param_2: i64,
}

impl Plugin for Test {
fn new(host: Host, tag: i32) -> Self {
impl Plugin for Simple {
fn new(host: Host, tag: Tag) -> Self {
init_log();

info!("init plugin with tag {}", tag);
Expand All @@ -48,19 +51,21 @@ impl Plugin for Test {
"Parameter 2".into(),
"Parameter 3".into(),
],
state: State::default(),
state: Default::default(),
voice_handler: Default::default(),
}
}

fn info(&self) -> Info {
info!("plugin {} will return info", self.tag);

InfoBuilder::new_effect("Simple", "Simple", self.param_names.len() as u32)
.want_new_tick()
InfoBuilder::new_full_gen("Simple", "Simple", self.param_names.len() as u32)
// InfoBuilder::new_effect("Simple", "Simple", self.param_names.len() as u32)
// .want_new_tick()
.build()
}

fn tag(&self) -> PluginTag {
fn tag(&self) -> Tag {
self.tag
}

Expand Down Expand Up @@ -143,10 +148,63 @@ impl Plugin for Test {
}

fn render(&mut self, input: &[[f32; 2]], output: &mut [[f32; 2]]) {
input.iter().zip(output).for_each(|(inp, outp)| {
outp[0] = inp[0] * 0.25;
outp[1] = inp[1] * 0.25;
});
if self.voice_handler.voices.len() < 1 {
// consider it an effect
input.iter().zip(output).for_each(|(inp, outp)| {
outp[0] = inp[0] * 0.25;
outp[1] = inp[1] * 0.25;
});
}
}

fn voice_handler(&mut self) -> &mut dyn VoiceHandler {
&mut self.voice_handler
}
}

#[derive(Debug, Default)]
struct SimpleVoiceHandler {
voices: HashMap<Tag, SimpleVoice>,
}

impl VoiceHandler for SimpleVoiceHandler {
fn trigger(&mut self, params: voice::Params, tag: Tag) -> &mut dyn Voice {
let voice = SimpleVoice::new(params, tag);
trace!("trigger voice {:?}", voice);
self.voices.insert(tag, voice);
self.voices.get_mut(&tag).unwrap()
}

fn release(&mut self, tag: Tag) {
trace!("release voice {:?}", self.voices.get(&tag));
}

fn kill(&mut self, tag: Tag) {
trace!("host wants to kill voice with tag {}", tag);
trace!("kill voice {:?}", self.voices.remove(&tag));
trace!("remaining voices count {}, {:?}", self.voices.len(), self.voices);
}

fn on_event(&mut self, tag: Tag, event: voice::Event) {
trace!("event {:?} for voice {:?}", event, self.voices.get(&tag));
}
}

#[derive(Debug)]
struct SimpleVoice {
tag: Tag,
params: voice::Params,
}

impl SimpleVoice {
pub fn new(params: voice::Params, tag: Tag) -> Self {
Self { tag, params }
}
}

impl Voice for SimpleVoice {
fn tag(&self) -> Tag {
self.tag
}
}

Expand All @@ -159,7 +217,7 @@ fn init_log() {

#[cfg(windows)]
fn _init_log() {
simple_logging::log_to_file(LOG_PATH, LevelFilter::Debug).unwrap();
simple_logging::log_to_file(LOG_PATH, LevelFilter::Trace).unwrap();
}

#[cfg(unix)]
Expand All @@ -173,7 +231,7 @@ fn _init_log() {
.open(LOG_PATH)
.unwrap();
let config = ConfigBuilder::new().set_time_to_local(true).build();
let _ = WriteLogger::init(LevelFilter::Debug, config, file).unwrap();
let _ = WriteLogger::init(LevelFilter::Trace, config, file).unwrap();
}

create_plugin!(Test);
create_plugin!(Simple);
40 changes: 35 additions & 5 deletions src/cxx/wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,20 +131,50 @@ void _stdcall PluginWrapper::Gen_Render(PWAV32FS DestBuffer, int &Length) {

TVoiceHandle _stdcall PluginWrapper::TriggerVoice(PVoiceParams VoiceParams,
intptr_t SetTag) {
return TVoiceHandle();
LevelParams init_levels = {
VoiceParams->InitLevels.Pan, VoiceParams->InitLevels.Vol,
VoiceParams->InitLevels.Pitch, VoiceParams->InitLevels.FCut,
VoiceParams->InitLevels.FRes,
};

LevelParams final_levels = {
VoiceParams->FinalLevels.Pan, VoiceParams->FinalLevels.Vol,
VoiceParams->FinalLevels.Pitch, VoiceParams->FinalLevels.FCut,
VoiceParams->FinalLevels.FRes,
};

Params params = {
init_levels,
final_levels,
};

return (TVoiceHandle)voice_handler_trigger(adapter, params, (int)SetTag);
}

void _stdcall PluginWrapper::Voice_Release(TVoiceHandle Handle) {}
void _stdcall PluginWrapper::Voice_Release(TVoiceHandle Handle) {
voice_handler_release(adapter, (void *)Handle);
}

void _stdcall PluginWrapper::Voice_Kill(TVoiceHandle Handle) {}
void _stdcall PluginWrapper::Voice_Kill(TVoiceHandle Handle) {
voice_handler_kill(adapter, (void *)Handle);
}

int _stdcall PluginWrapper::Voice_ProcessEvent(TVoiceHandle Handle, int EventID,
int EventValue, int Flags) {
Message message = {
(intptr_t)EventID,
(intptr_t)EventValue,
(intptr_t)Flags,
};

voice_handler_on_event(adapter, (void *)Handle, message);

return 0;
}

int _stdcall PluginWrapper::Voice_Render(TVoiceHandle Handle,
PWAV32FS DestBuffer, int &Length) {
int _stdcall PluginWrapper::Voice_Render(TVoiceHandle, PWAV32FS, int &) {
// Deprecated:
// https://forum.image-line.com/viewtopic.php?f=100&t=199515#p1371655
return 0;
}

Expand Down
27 changes: 25 additions & 2 deletions src/cxx/wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ struct MidiMessage;
struct PluginAdapter;
struct TimeSignature;

// from plugin.rs
struct Info {
uint32_t sdk_version;
char *long_name;
Expand All @@ -19,6 +20,20 @@ struct Info {
uint32_t num_out_voices;
};

// from voice.rs
struct LevelParams {
float pan;
float vol;
float pitch;
float mod_x;
float mod_y;
};

struct Params {
LevelParams init_levels;
LevelParams final_levels;
};

class PluginWrapper : public TFruityPlug {
public:
PluginWrapper(TFruityPlugHost *Host, int Tag, PluginAdapter *adapter,
Expand Down Expand Up @@ -81,8 +96,16 @@ extern "C" void plugin_gen_render(PluginAdapter *adapter, float dest[1][2],
extern "C" void plugin_midi_in(PluginAdapter *adapter, MidiMessage message);
extern "C" void plugin_save_state(PluginAdapter *adapter, IStream *istream);
extern "C" void plugin_load_state(PluginAdapter *adapter, IStream *istream);
extern "C" int32_t istream_read(void *istream, uint8_t *data,
uint32_t size, uint32_t *read);

extern "C" intptr_t voice_handler_trigger(PluginAdapter *adpater, Params params,
int tag);
extern "C" void voice_handler_release(PluginAdapter *adpater, void *voice);
extern "C" void voice_handler_kill(PluginAdapter *adpater, void *voice);
extern "C" void voice_handler_on_event(PluginAdapter *adpater, void *voice,
Message message);

extern "C" int32_t istream_read(void *istream, uint8_t *data, uint32_t size,
uint32_t *read);
extern "C" int32_t istream_write(void *istream, const uint8_t *data,
uint32_t size, uint32_t *write);

Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub mod ffi {

pub mod host;
pub mod plugin;
pub mod voice;

use std::ffi::{CStr, CString};
use std::fmt;
Expand All @@ -104,6 +105,9 @@ use log::{debug, error};
pub use ffi::{MidiMessage, TimeSignature};
use plugin::PluginAdapter;

/// An identefier the host uses to identify plugin and voice instances.
pub type Tag = i32;

/// Current FL SDK version.
pub const CURRENT_SDK_VERSION: u32 = 1;

Expand Down
Loading

0 comments on commit 73d8f1d

Please sign in to comment.