Skip to content

Commit

Permalink
Port TFruityPlugHost PlugMsg methods (#83)
Browse files Browse the repository at this point in the history
- update install script for Windows
  • Loading branch information
dmitryrec authored May 20, 2020
1 parent 635aacb commit 5252354
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 40 deletions.
26 changes: 17 additions & 9 deletions examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use fpsdk::plugin::message;
use fpsdk::plugin::{self, Info, InfoBuilder, Plugin, StateReader, StateWriter};
use fpsdk::voice::{self, ReceiveVoiceHandler, SendVoiceHandler, Voice};
use fpsdk::{
create_plugin, AsRawPtr, MessageBoxFlags, MidiMessage, Note, Notes, NotesFlags,
create_plugin, AsRawPtr, FromRawPtr, MessageBoxFlags, MidiMessage, Note, Notes, NotesFlags,
ProcessParamFlags, TimeFormat, ValuePtr,
};

Expand Down Expand Up @@ -150,6 +150,7 @@ impl Plugin for Simple {
// https://forum.image-line.com/viewtopic.php?f=100&t=199371
// https://forum.image-line.com/viewtopic.php?f=100&t=199258
.with_out_voices(1)
.loop_out()
.midi_out()
.build()
}
Expand Down Expand Up @@ -184,7 +185,7 @@ impl Plugin for Simple {
})
.unwrap_or_else(|e| error!("error reading value from state {}", e));
}

fn on_message(&mut self, message: host::Message) -> Box<dyn AsRawPtr> {
self.host.on_message(
self.tag,
Expand All @@ -199,17 +200,24 @@ impl Plugin for Simple {
if enabled {
self.show_annoying_message();
// self.host.on_message(self.tag, message::ActivateMidi);
self.host.loop_out(
self.tag,
ValuePtr::from_raw_ptr(format!("{:?}", message).as_raw_ptr()),
);
}

self.host
.on_parameter(self.tag, 0, ValuePtr::new(0.123456789_f32.as_raw_ptr()));
self.host.on_parameter(
self.tag,
0,
ValuePtr::from_raw_ptr(0.123456789_f32.as_raw_ptr()),
);
}

// self.host.midi_out(self.tag, MidiMessage {
// status: 0x90,
// data1: 60,
// data2: 100,
// port: 2,
// status: 0x90,
// data1: 60,
// data2: 100,
// port: 2,
// });

Box::new(0)
Expand Down Expand Up @@ -238,7 +246,7 @@ impl Plugin for Simple {

// looks like doesn't work
fn loop_in(&mut self, message: ValuePtr) {
trace!("{:?} loop_in", message);
trace!("{} loop_in", message.get::<String>());
}

fn process_param(
Expand Down
38 changes: 27 additions & 11 deletions install.win.bat
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
:: Usage:
:: install.win.bat name destination_name [plugins_dir]
:: install.win.bat name destination_name type_of_plugin [plugins_dir]

@echo off

set name=%1
set dest_name=%2
set plugins_dir="C:\Program Files\Image-Line\FL Studio 20\Plugins\Fruity"
set args_count=0
set flag=false
set incorrect_args_count=false
set type_flag=false

for %%x in (%*) do Set /A args_count+=1

if %args_count% lss 2 set flag=true
if %args_count% gtr 3 set flag=true
if "%flag%"=="true" (
echo "Usage: install.win.bat name destination_name [plugins_dir]"
if %args_count% lss 3 set incorrect_args_count=true
if %args_count% gtr 4 set incorrect_args_count=true
if "%incorrect_args_count%"=="true" (
echo "Usage: install.win.bat name destination_name type_of_plugin [plugins_dir]"
exit /B 87
)

if %args_count%==3 (
set plugins_dir=%3
if "%3"=="-e" (
set type=Effects
set type_flag=true
)

if "%3"=="-g" (
set type=Generators
set type_flag=true
)

if "%type_flag%"=="false" (
echo "please type '-e' or '-g'"
exit /B 87
)

if %args_count%==4 (
set plugins_dir=%4
)

rd /s /q %plugins_dir%\Effects\%dest_name%
md %plugins_dir%\Effects\%dest_name%
move target\release\examples\%name%.dll %plugins_dir%\Effects\%dest_name%\%dest_name%_x64.dll
rd /s /q %plugins_dir%\%type%\%dest_name%
md %plugins_dir%\%type%\%dest_name%
move target\release\examples\%name%.dll %plugins_dir%\%type%\%dest_name%\%dest_name%_x64.dll
8 changes: 8 additions & 0 deletions src/cxx/wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,14 @@ void host_midi_out_del(void *host, TPluginTag tag, unsigned char status,
((TFruityPlugHost *)host)->MIDIOut_Delayed(tag, (intptr_t)msg);
}

void host_loop_out(void *host, TPluginTag tag, intptr_t msg) {
((TFruityPlugHost *)host)->PlugMsg_Delayed(tag, msg);
}

void host_loop_kill(void *host, TPluginTag tag, intptr_t msg) {
((TFruityPlugHost *)host)->PlugMsg_Kill(tag, msg);
}

void host_release_voice(void *host, intptr_t tag) {
((TFruityPlugHost *)host)->Voice_Release(tag);
}
Expand Down
2 changes: 2 additions & 0 deletions src/cxx/wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ extern "C" void host_midi_out(void *host, TPluginTag tag, unsigned char status,
unsigned char port);
extern "C" void host_midi_out_del(void *host, TPluginTag tag, unsigned char
status, unsigned char data1, unsigned char data2, unsigned char port);
extern "C" void host_loop_out(void *host, TPluginTag tag, intptr_t msg);
extern "C" void host_loop_kill(void *host, TPluginTag tag, intptr_t msg);

extern "C" void host_release_voice(void *host, intptr_t tag);
extern "C" void host_kill_voice(void *host, intptr_t tag);
Expand Down
21 changes: 21 additions & 0 deletions src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,25 @@ impl Host {
};
}

/// **MAY NOT WORK**
///
/// Ask for a message to be dispatched to itself when the current mixing tick will be played
/// (to synchronize stuff)
///
/// (see [`Plugin::loop_in`](../plugin/trait.Plugin.html#method.loop_in)).
///
/// The message is guaranteed to be dispatched, however it could be sent immediately if it
/// couldn't be buffered (it's only buffered when playing).
pub fn loop_out(&mut self, tag: plugin::Tag, message: ValuePtr) {
unsafe { host_loop_out(*self.host_ptr.get_mut(), tag.0, message.0) };
}

/// Remove the buffered message scheduled by
/// [`Host::loop_out`](struct.Host.html#method.loop_out), so that it will never be dispatched.
pub fn loop_kill(&mut self, tag: plugin::Tag, message: ValuePtr) {
unsafe { host_loop_kill(*self.host_ptr.get_mut(), tag.0, message.0) };
}

/// Get [`Voicer`](struct.Voicer.html)
pub fn voice_handler(&self) -> Arc<Mutex<Voicer>> {
Arc::clone(&self.voicer)
Expand Down Expand Up @@ -180,6 +199,8 @@ extern "C" {
data2: c_uchar,
port: c_uchar,
);
fn host_loop_out(host: *mut c_void, tag: intptr_t, message: intptr_t);
fn host_loop_kill(host: *mut c_void, tag: intptr_t, message: intptr_t);
}

/// Use this to manually release, kill and notify voices about events.
Expand Down
37 changes: 19 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,24 +186,6 @@ extern "C" {
fn alloc_real_cstr(raw_str: *mut c_char) -> *mut c_char;
}

/// Raw pointer to value.
#[derive(Debug)]
pub struct ValuePtr(intptr_t);

impl ValuePtr {
/// Constructor.
pub fn new(ptr: intptr_t) -> Self {
Self(ptr)
}

/// Get value.
///
/// See [`FromRawPtr`](trait.FromRawPtr.html) for implemented types.
pub fn get<T: FromRawPtr>(&self) -> T {
T::from_raw_ptr(self.0)
}
}

/// For types, which can be represented as `intptr_t`.
pub trait AsRawPtr {
/// Conversion method.
Expand Down Expand Up @@ -316,6 +298,25 @@ impl FromRawPtr for bool {
}
}

/// Raw pointer to value.
#[derive(Debug)]
pub struct ValuePtr(intptr_t);

impl ValuePtr {
/// Get value.
///
/// See [`FromRawPtr`](trait.FromRawPtr.html) for implemented types.
pub fn get<T: FromRawPtr>(&self) -> T {
T::from_raw_ptr(self.0)
}
}

impl FromRawPtr for ValuePtr {
fn from_raw_ptr(value: intptr_t) -> Self {
ValuePtr(value)
}
}

bitflags! {
/// Parameter flags.
pub struct ParameterFlags: isize {
Expand Down
3 changes: 1 addition & 2 deletions src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ pub trait Plugin: std::fmt::Debug + RefUnwindSafe + Send + Sync + 'static {
/// Can be called from GUI or mixer threads.
fn midi_in(&mut self, _message: MidiMessage) {}
/// **MAY NOT WORK**
///
///
/// This gets called with a new buffered message to the plugin itself.
fn loop_in(&mut self, _message: ValuePtr) {}
}
Expand Down Expand Up @@ -646,7 +646,6 @@ pub unsafe extern "C" fn plugin_load_state(adapter: *mut PluginAdapter, stream:
(*adapter).0.load_state(StateReader(stream));
}


/// [`Plugin::loop_in`](Plugin.html#method.loop_in) FFI.
///
/// It supposed to be used internally. Don't use it.
Expand Down

0 comments on commit 5252354

Please sign in to comment.