midi_sine/
midi_sine.rs

1// use the jack bindings
2extern crate easyjack as jack;
3
4// use nix for signal handling
5// see simple_client example for some description of how this works
6extern crate nix;
7
8use nix::sys::signal;
9use std::f32::consts;
10use std::f32;
11use std::sync::atomic;
12use std::sync::mpsc::{SyncSender, Receiver};
13use std::sync::mpsc;
14use std::thread;
15use std::time::Duration;
16
17static RUNNING: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;
18
19type IPort = jack::InputPortHandle<jack::MidiEvent>;
20type OPort = jack::OutputPortHandle<jack::DefaultAudioSample>;
21
22/// struct to handle metadata operations
23struct MetadataHandler {
24    outgoing: SyncSender<[jack::DefaultAudioSample; 128]>,
25}
26
27impl MetadataHandler {
28    pub fn new(outgoing: SyncSender<[jack::DefaultAudioSample; 128]>) -> Self {
29        MetadataHandler { outgoing: outgoing }
30    }
31}
32
33impl jack::MetadataHandler for MetadataHandler {
34    fn sample_rate_changed(&mut self, srate: jack::NumFrames) -> i32 {
35        println!("updating sample rate: {}", srate);
36
37        let f = AudioHandler::calc_note_freqs(srate);
38        match self.outgoing.send(f) {
39            Ok(_) => 0,
40            Err(_) => 0
41        }
42    }
43
44    fn callbacks_of_interest(&self) -> Vec<jack::MetadataHandlers> {
45        vec![jack::MetadataHandlers::SampleRate]
46    }
47}
48
49/// struct to handle audio event loop
50struct AudioHandler {
51    input:  jack::InputPortHandle<jack::MidiEvent>,
52    output: jack::OutputPortHandle<jack::DefaultAudioSample>,
53
54    // TODO explain what this is all about
55    ramp:       jack::DefaultAudioSample,
56    note_on:    jack::DefaultAudioSample,
57    note:       u8,
58    note_freqs: [jack::DefaultAudioSample; 128],
59
60    incoming: Receiver<[jack::DefaultAudioSample; 128]>,
61}
62
63impl AudioHandler {
64    pub fn new(input: IPort, output: OPort, incoming: Receiver<[jack::DefaultAudioSample; 128]>)
65        -> AudioHandler
66    {
67        let freqs = [0.0; 128];
68        AudioHandler {
69            input:      input,
70            output:     output,
71            ramp:       0.0,
72            note_on:    0.0,
73            note:       0,
74            note_freqs: freqs,
75            incoming:   incoming,
76        }
77    }
78
79    pub fn calc_note_freqs(srate: jack::NumFrames) -> [jack::DefaultAudioSample; 128] {
80        println!("recalculating note frequencies");
81        let mut freqs = [0.0; 128];
82        print!("new_freqs: ");
83        for i in 0..128 {
84            let a = 2.0 * (440.0 / 32.0);
85            let b = 2.0_f32.powf( (i as f32 - 9.0) / 12.0 );
86            freqs[i] = a * b / srate as f32;
87
88            print!("{},", freqs[i]);
89        }
90        println!("");
91
92
93        freqs
94    }
95}
96
97impl jack::ProcessHandler for AudioHandler {
98    fn process(&mut self, ctx: &jack::CallbackContext, nframes: jack::NumFrames) -> i32 {
99        let output_buffer = self.output.get_write_buffer(nframes, &ctx);
100        let input_buffer  = self.input.get_read_buffer(nframes, &ctx);
101
102        let mut event_index = 0;
103        let event_count = input_buffer.len();
104
105        for i in 0..(nframes as usize) {
106            if event_index < event_count {
107                let event = input_buffer.get(event_index);
108
109                println!("evi={} evt={}, i={}", event_index, event.get_jack_time(), i);
110                if event.get_jack_time() == i as jack::NumFrames {
111                    let buf = event.raw_midi_bytes();
112
113                    if buf[0] & 0x90 == 0x90 {
114                        println!("note on!");
115                        self.note    = buf[1];
116                        self.note_on = 1.0;
117                    } else if buf[0] & 0x90 == 0x80 {
118                        println!("note off!");
119                        self.note    = buf[1];
120                        self.note_on = 0.0;
121                    }
122                    event_index += 1;
123                    if event_index < event_count {
124                        event_index += 1;
125                    }
126                }
127            }
128
129            self.ramp += self.note_freqs[self.note as usize];
130            self.ramp = if self.ramp > 1.0 { self.ramp - 2.0 } else { self.ramp };
131
132            let s = (2.0 * (consts::PI) * self.ramp).sin();
133            output_buffer[i] = self.note_on*s;
134            // println!("output_buffer[{}] = {}", i, output_buffer[i]);
135        }
136
137        match self.incoming.try_recv() {
138            Ok(freqs) => self.note_freqs = freqs,
139            Err(_) => (),
140        };
141
142        0
143    }
144}
145
146extern "C" fn handle_sigint(_: i32) {
147    RUNNING.store(false, atomic::Ordering::SeqCst);
148}
149
150fn main() {
151    // register a signal handler (see comments at top of file)
152    let action = signal::SigAction::new(
153        signal::SigHandler::Handler(handle_sigint),
154        signal::SaFlags::empty(),
155        signal::SigSet::empty());
156
157    unsafe { signal::sigaction(signal::Signal::SIGINT, &action) }.unwrap();
158
159    // set our global atomic to true
160    RUNNING.store(true, atomic::Ordering::SeqCst);
161
162
163    let mut c = jack::Client::open("midi_sine", jack::options::NO_START_SERVER).unwrap().0;
164    let i = c.register_input_midi_port("midi_in").unwrap();
165    let o = c.register_output_audio_port("audio_out").unwrap();
166
167    let (tx, rx) = mpsc::sync_channel(1);
168
169    let handler = AudioHandler::new(i, o, rx);
170    c.set_process_handler(handler).unwrap();
171
172    let handler = MetadataHandler::new(tx);
173    c.set_metadata_handler(handler).unwrap();
174
175    c.activate().unwrap();
176
177    while RUNNING.load(atomic::Ordering::SeqCst) {
178        thread::sleep(Duration::from_millis(1000));
179    }
180    println!("tearing down");
181    c.close().unwrap();
182}