2022-08-10 17:15:03 +00:00
// Copyright (c) 2022 Weird Constructor <weirdconstructor@gmail.com>
// This file is a part of HexoDSP. Released under GPL-3.0-or-later.
// See README.md and COPYING for details.
2022-08-16 01:52:45 +00:00
use crate ::dsp ::{ at , inp , denorm , out_idx , DspNode , LedPhaseVals , NodeContext , NodeId , ProcBuf , SAtom } ;
2022-08-13 22:32:48 +00:00
use crate ::nodes ::{ HxMidiEvent , MidiEventPointer , NodeAudioContext , NodeExecContext } ;
2022-08-16 01:52:45 +00:00
use synfx_dsp ::{ GateSignal , TrigSignal } ;
2022-08-10 17:15:03 +00:00
#[ macro_export ]
macro_rules ! fa_midip_chan {
( $formatter : expr , $v : expr , $denorm_v : expr ) = > { {
write! ( $formatter , " {} " , $v . round ( ) as usize )
} } ;
}
2022-08-12 01:51:46 +00:00
#[ macro_export ]
macro_rules ! fa_midip_gmode {
( $formatter : expr , $v : expr , $denorm_v : expr ) = > { {
let s = match ( $v . round ( ) as usize ) {
0 = > " MIDI " ,
1 = > " Trigger " ,
2 = > " Gate Len " ,
_ = > " ? " ,
} ;
write! ( $formatter , " {} " , s )
} } ;
}
2022-08-10 17:15:03 +00:00
/// The (stereo) output port of the plugin
#[ derive(Debug, Clone) ]
pub struct MidiP {
2022-08-13 22:32:48 +00:00
next_gate : i8 ,
cur_note : u8 ,
cur_gate : u8 ,
cur_vel : f32 ,
2022-08-15 03:08:01 +00:00
trig_sig : TrigSignal ,
2022-08-16 01:52:45 +00:00
gate_sig : GateSignal ,
2022-08-10 17:15:03 +00:00
}
impl MidiP {
pub fn new ( _nid : & NodeId ) -> Self {
2022-08-16 01:52:45 +00:00
Self {
next_gate : 0 ,
cur_note : 0 ,
cur_gate : 0 ,
cur_vel : 0.0 ,
trig_sig : TrigSignal ::new ( ) ,
gate_sig : GateSignal ::new ( ) ,
}
2022-08-10 17:15:03 +00:00
}
pub const chan : & 'static str = " MidiP chan \n MIDI Channel 0 to 15 \n " ;
2022-08-12 01:51:46 +00:00
pub const gmode : & 'static str = " MidiP gmode \n MIDI gate mode. \n - 'MIDI' gate same as MIDI input \n - 'Trigger' output only triggers on 'gate' output \n - 'Gate Len' output gate with the length of the 'gatel' parameter \n " ;
2022-08-15 03:08:01 +00:00
pub const glen : & 'static str = " MidiP glen \n MIDI gate length \n \
If ' gmode ' is set to ' Gate Len ' this controls and overrides the gate length on a MIDI \
note event . ' Trigger ' will just send a short trigger when a note event is received . \
' MIDI ' means the gate reflects the note on / off duration . " ;
2022-08-10 17:15:03 +00:00
pub const det : & 'static str = " MidiP det \n Detune input pitch a bit \n Range: (-1..1) " ;
pub const freq : & 'static str =
" MidiP freq \n MIDI note frequency, detuned by 'det'. \n Range: (-1..1) " ;
pub const gate : & 'static str = " MidiP gate \n MIDI note gate \n Range: (0..1) " ;
pub const vel : & 'static str = " MidiP vel \n MIDI note velocity \n Range: (0..1) " ;
pub const ch1 : & 'static str = " MidiP ch1 \n Audio channel 1 (left) \n Range: (-1..1) " ;
pub const ch2 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch3 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch4 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch5 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch6 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch7 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch8 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch9 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch10 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch11 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch12 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch13 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch14 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch15 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch16 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const ch17 : & 'static str = " MidiP ch2 \n Audio channel 2 (right) \n Range: (-1..1) " ;
pub const DESC : & 'static str = " Audio Output Port \n \n \
This output port node allows you to send audio signals \
to audio devices or tracks in your DAW . " ;
pub const HELP : & 'static str = r #" Audio Output Port
This output port node allows you to send audio signals to audio devices
or tracks in your DAW . If you need a stereo output but only have a mono
signal you can use the ' mono ' setting to duplicate the signal on the ' ch1 '
input to the second channel ' ch2 ' .
" #;
}
impl DspNode for MidiP {
fn outputs ( ) -> usize {
0
}
2022-08-15 03:08:01 +00:00
fn set_sample_rate ( & mut self , srate : f32 ) {
self . trig_sig . set_sample_rate ( srate ) ;
2022-08-16 01:52:45 +00:00
self . gate_sig . set_sample_rate ( srate ) ;
2022-08-15 03:08:01 +00:00
}
fn reset ( & mut self ) {
self . trig_sig . reset ( ) ;
2022-08-16 01:52:45 +00:00
self . gate_sig . reset ( ) ;
2022-08-15 03:08:01 +00:00
}
2022-08-10 17:15:03 +00:00
#[ inline ]
fn process < T : NodeAudioContext > (
& mut self ,
ctx : & mut T ,
ectx : & mut NodeExecContext ,
_nctx : & NodeContext ,
atoms : & [ SAtom ] ,
2022-08-12 01:51:46 +00:00
inputs : & [ ProcBuf ] ,
2022-08-10 17:15:03 +00:00
outputs : & mut [ ProcBuf ] ,
ctx_vals : LedPhaseVals ,
) {
2022-08-12 01:51:46 +00:00
let det = inp ::MidiP ::det ( inputs ) ;
2022-08-16 01:52:45 +00:00
let glen = inp ::MidiP ::glen ( inputs ) ;
2022-08-12 01:51:46 +00:00
let chan = at ::MidiP ::chan ( atoms ) ;
2022-08-15 03:08:01 +00:00
let gmode = at ::MidiP ::gmode ( atoms ) ;
2022-08-10 20:42:48 +00:00
let out_i = out_idx ::MidiP ::gate ( ) ;
2022-08-10 17:15:03 +00:00
let ( freq , r ) = outputs . split_at_mut ( out_i ) ;
let ( gate , vel ) = r . split_at_mut ( 1 ) ;
let freq = & mut freq [ 0 ] ;
let gate = & mut gate [ 0 ] ;
let vel = & mut vel [ 0 ] ;
2022-08-13 22:32:48 +00:00
let midip_channel = ( chan . i ( ) as usize % 16 ) as u8 ;
2022-08-12 01:51:46 +00:00
2022-08-13 22:32:48 +00:00
let mut ptr = MidiEventPointer ::new ( & ectx . midi_notes [ .. ] ) ;
2022-08-11 03:11:26 +00:00
2022-08-15 03:08:01 +00:00
let gmode = gmode . i ( ) ;
2022-08-13 22:32:48 +00:00
for frame in 0 .. ctx . nframes ( ) {
2022-08-16 01:52:45 +00:00
let gate_len = denorm ::MidiP ::glen ( glen , frame ) ;
2022-08-13 22:32:48 +00:00
if self . next_gate > 0 {
self . cur_gate = 1 ;
} else if self . next_gate < 0 {
self . cur_gate = 0 ;
}
self . next_gate = 0 ;
while let Some ( ev ) = ptr . next_at ( frame ) {
match ev {
HxMidiEvent ::NoteOn { channel , note , vel } = > {
if channel ! = midip_channel {
continue ;
}
if self . cur_gate > 0 {
self . next_gate = 1 ;
self . cur_gate = 0 ;
} else {
self . cur_gate = 1 ;
}
2022-08-16 01:52:45 +00:00
println! ( " NOTE ON " ) ;
2022-08-15 03:08:01 +00:00
self . trig_sig . trigger ( ) ;
2022-08-16 01:52:45 +00:00
self . gate_sig . trigger ( ) ;
2022-08-13 22:32:48 +00:00
self . cur_note = note ;
self . cur_vel = vel ;
}
HxMidiEvent ::NoteOff { channel , note } = > {
2022-08-16 01:52:45 +00:00
println! ( " NOTE OFF " ) ;
2022-08-13 22:32:48 +00:00
if channel ! = midip_channel {
continue ;
}
if self . cur_note = = note {
self . next_gate = - 1 ;
}
}
_ = > ( ) ,
2022-08-11 03:11:26 +00:00
}
}
2022-08-12 01:47:15 +00:00
2022-08-15 03:08:01 +00:00
match gmode {
1 = > {
gate . write ( frame , self . trig_sig . next ( ) ) ;
}
2022-08-16 01:52:45 +00:00
2 = > {
println! ( " GOGOGO {} {} " , gate_len , self . next_gate ) ;
if self . next_gate > 0 {
gate . write ( frame , 0.0 ) ;
} else {
gate . write ( frame , self . gate_sig . next ( gate_len ) ) ;
}
}
2022-08-15 03:08:01 +00:00
_ = > {
gate . write ( frame , if self . cur_gate > 0 { 1.0 } else { 0.0 } ) ;
}
}
2022-08-13 22:32:48 +00:00
let note = ( self . cur_note as f32 - 69.0 ) / 120.0 ;
let note = note + det . read ( frame ) ;
2022-08-14 05:22:58 +00:00
//d// println!("FRAME: {} => gate={}, freq={}, next_gate={}", frame, self.cur_gate, note, self.next_gate);
2022-08-13 22:32:48 +00:00
freq . write ( frame , note ) ;
vel . write ( frame , self . cur_vel as f32 ) ;
2022-08-10 17:15:03 +00:00
}
let last_val = gate . read ( ctx . nframes ( ) - 1 ) ;
ctx_vals [ 0 ] . set ( last_val ) ;
}
}