Commit 4ba4ca13e7973216b4183f63e28393f41614ba18
checkpoint
Michael Williams committed on 5/13/2018, 6:11:30 AMParent: 9b8912a81188690277f8add60b236015174da8c9
Files changed
src/main.rs | changed |
src/clock.rs | added |
src/control.rs | added |
src/main.rs | ||
---|---|---|
@@ -46,66 +46,83 @@ | ||
46 | 46 … | // extern crate ctrlc; |
47 | 47 … | |
48 | 48 … | use std::char; |
49 | 49 … | use ncurses::{WchResult}; |
50 | -// use std::sync::atomic::{AtomicBool, Ordering}; | |
51 | -// use std::sync::Arc; | |
50 … | +use std::thread::{sleep,spawn}; | |
51 … | +use std::time::{Duration}; | |
52 | 52 … | |
53 … | +mod clock; | |
53 | 54 … | |
54 | 55 … | // https://unicode.org/charts/PDF/U0000.pdf |
55 | 56 … | static CHAR_SPACE: u32 = 0x0020; |
56 | 57 … | static CHAR_RETURN: u32 = 0x000D; |
57 | 58 … | static CHAR_NEWLINE: u32 = 0x000A; |
58 | 59 … | |
59 | -fn main() { | |
60 | - // let locale_conf = LcCategory::all; | |
61 | - // setlocale(locale_conf, "en_US.UTF-8"); | |
60 … | +fn main () { | |
61 … | + clock(); | |
62 … | + // terminal_interface(); | |
63 … | + | |
64 … | + loop { | |
65 … | + sleep(Duration::new(10, 0)); | |
66 … | + } | |
67 … | +} | |
62 | 68 … | |
63 | - /* Setup ncurses. */ | |
64 | - ncurses::initscr(); | |
69 … | +fn clock () { | |
70 … | + spawn(move|| { | |
71 … | + let time_signature = clock::TimeSignature { | |
72 … | + nanos_per_beat: BEATS_PER_MINUTE / SECONDS_PER_MINUTE * NANOS_PER_SECOND, | |
73 … | + ticks_per_beat: DEFAULT_TICKS_PER_BEAT, | |
74 … | + beats_per_measure: DEFAULT_BEATS_PER_MEASURE | |
75 … | + }; | |
76 … | + let mut clock = clock::Clock::new(time_signature); | |
77 … | + loop { | |
78 … | + clock.tick(); | |
79 … | + println!("{:?}", clock.get_time()); | |
80 … | + } | |
81 … | + }); | |
82 … | +} | |
65 | 83 … | |
66 | - /* Enable mouse events. */ | |
67 | - ncurses::mousemask(ncurses::ALL_MOUSE_EVENTS as ncurses::mmask_t, None); | |
84 … | +fn terminal_interface () { | |
85 … | + spawn(move|| { | |
86 … | + let locale_conf = ncurses::LcCategory::all; | |
87 … | + ncurses::setlocale(locale_conf, "en_US.UTF-8"); | |
68 | 88 … | |
69 | - /* Allow for extended keyboard (like F1). */ | |
70 | - ncurses::keypad(ncurses::stdscr(), true); | |
71 | - ncurses::noecho(); | |
89 … | + /* Setup ncurses. */ | |
90 … | + ncurses::initscr(); | |
72 | 91 … | |
92 … | + /* Enable mouse events. */ | |
93 … | + ncurses::mousemask(ncurses::ALL_MOUSE_EVENTS as ncurses::mmask_t, None); | |
73 | 94 … | |
74 | - /* | |
75 | - let running = Arc::new(AtomicBool::new(true)); | |
76 | - let r = running.clone(); | |
77 | - ctrlc::set_handler(move || { | |
78 | - r.store(false, Ordering::SeqCst); | |
79 | - }).expect("Error setting Ctrl-C handler"); | |
95 … | + /* Allow for extended keyboard (like F1). */ | |
96 … | + ncurses::keypad(ncurses::stdscr(), true); | |
97 … | + ncurses::noecho(); | |
80 | 98 … | |
81 | - while running.load(Ordering::SeqCst) { | |
82 | - */ | |
83 | - loop { | |
84 | - let ch = ncurses::wget_wch(ncurses::stdscr()); | |
99 … | + loop { | |
100 … | + let ch = ncurses::wget_wch(ncurses::stdscr()); | |
85 | 101 … | |
86 | - match ch { | |
87 | - Some(WchResult::KeyCode(ncurses::KEY_MOUSE)) => { | |
88 | - tap(); | |
89 | - } | |
102 … | + match ch { | |
103 … | + Some(WchResult::KeyCode(ncurses::KEY_MOUSE)) => { | |
104 … | + tap(); | |
105 … | + } | |
90 | 106 … | |
91 | - // https://github.com/jeaye/ncurses-rs/blob/master/src/constants.rs | |
92 | - Some(WchResult::KeyCode(_)) => {} | |
107 … | + // https://github.com/jeaye/ncurses-rs/blob/master/src/constants.rs | |
108 … | + Some(WchResult::KeyCode(_)) => {} | |
93 | 109 … | |
94 | - // Some(WchResult::KeyCode(KEY_ENTER)) => beat(), | |
95 | - Some(WchResult::Char(ch)) => { | |
96 | - if (ch == CHAR_SPACE || ch == CHAR_NEWLINE) { | |
97 | - tap(); | |
110 … | + // Some(WchResult::KeyCode(KEY_ENTER)) => beat(), | |
111 … | + Some(WchResult::Char(ch)) => { | |
112 … | + if (ch == CHAR_SPACE || ch == CHAR_NEWLINE) { | |
113 … | + tap(); | |
114 … | + } | |
98 | 115 … | } |
116 … | + | |
117 … | + None => {} | |
99 | 118 … | } |
100 | 119 … | |
101 | - None => {} | |
120 … | + ncurses::refresh(); | |
102 | 121 … | } |
103 | 122 … | |
104 | - ncurses::refresh(); | |
105 | - } | |
106 | - | |
107 | - ncurses::endwin(); | |
123 … | + ncurses::endwin(); | |
124 … | + }); | |
108 | 125 … | } |
109 | 126 … | |
110 | 127 … | fn tap () { |
111 | 128 … | ncurses::attron(ncurses::A_BOLD()); |
src/clock.rs | ||
---|---|---|
@@ -1,0 +1,87 @@ | ||
1 … | +// inspired by https://github.com/mmckegg/rust-loop-drop/blob/master/src/midi_time.rs | |
2 … | +// http://www.deluge.co/?q=midi-tempo-bpm | |
3 … | + | |
4 … | +use std::time::{Duration, Instant}; | |
5 … | +use std::thread::{sleep}; | |
6 … | + | |
7 … | +pub type Time = Instant; | |
8 … | + | |
9 … | +pub type Nanos = u64; | |
10 … | +pub type Ticks = u64; | |
11 … | +pub type Beats = u64; | |
12 … | +pub type Measures = u64; | |
13 … | + | |
14 … | +static SECONDS_PER_MINUTE: u64 = 60; | |
15 … | +static NANOS_PER_SECOND: u64 = 1_000_000; | |
16 … | +static BEATS_PER_MINUTE: u64 = 60; | |
17 … | +static DEFAULT_TICKS_PER_BEAT: u64 = 1; | |
18 … | +static DEFAULT_BEATS_PER_MEASURE: u64 = 4; | |
19 … | + | |
20 … | + | |
21 … | +pub struct TimeSignature { | |
22 … | + nanos_per_beat: u64, // tempo | |
23 … | + clicks_per_beat: u64, // meter: notes per beat | |
24 … | + beats_per_bar: u64 // meter | |
25 … | +} | |
26 … | + | |
27 … | +impl TimeSignature { | |
28 … | + pub fn new (beats_per_minute: f64) { | |
29 … | + let beats_per_nano = ticks_per_minute | |
30 … | + } | |
31 … | + | |
32 … | + pub fn nanos_per_tick (&self) -> u64 { | |
33 … | + (self.nanos_per_beat / self.ticks_per_beat) as u64 | |
34 … | + } | |
35 … | + | |
36 … | + pub fn ticks_since (&self, diff_duration: Duration) -> u64 { | |
37 … | + let total_nanos = diff_duration.as_secs() * 1_000_000_000 + diff_duration.subsec_nanos() as u64; | |
38 … | + self.nanos_per_tick() - total_nanos | |
39 … | + } | |
40 … | +} | |
41 … | + | |
42 … | + | |
43 … | +pub struct Clock { | |
44 … | + time: Time, | |
45 … | + time_signature: TimeSignature | |
46 … | +} | |
47 … | + | |
48 … | +pub struct ClockMessage { | |
49 … | +} | |
50 … | + | |
51 … | +impl Clock { | |
52 … | + pub fn new (time_signature: TimeSignature) -> Self { | |
53 … | + Self { | |
54 … | + time: Instant::now(), | |
55 … | + time_signature | |
56 … | + } | |
57 … | + } | |
58 … | + | |
59 … | + pub fn get_time (&self) -> Time { | |
60 … | + self.time | |
61 … | + } | |
62 … | + | |
63 … | + // https://github.com/BookOwl/fps_clock/blob/master/src/lib.rs | |
64 … | + pub fn tick (&mut self) -> u64 { | |
65 … | + let diff_duration = self.time.elapsed(); | |
66 … | + let diff_nanos = self.time_signature.nanos_since(diff_duration); | |
67 … | + if diff_nanos > 0 { | |
68 … | + sleep(Duration::new(0, diff_nanos as u32)) | |
69 … | + }; | |
70 … | + self.time = Instant::now(); | |
71 … | + diff_nanos | |
72 … | + } | |
73 … | +} | |
74 … | + | |
75 … | +/* | |
76 … | +pub fn nanos_from_ticks (ticks: Ticks, time_signature: TimeSignature) -> Nanos { | |
77 … | + ticks * time_signature.nanos_per_beat | |
78 … | +} | |
79 … | + | |
80 … | +pub fn ticks_from_beats (beats: Beats, time_signature: TimeSignature) -> Ticks { | |
81 … | + beats * time_signature.ticks_per_beat | |
82 … | +} | |
83 … | + | |
84 … | +pub fn ticks_from_measure (measures: Measures, time_signature: TimeSignature) -> Ticks { | |
85 … | + measures * time_signature.beats_per_measure * time_signature.ticks_per_beat | |
86 … | +} | |
87 … | +*/ |
src/control.rs | ||
---|---|---|
@@ -1,0 +1,40 @@ | ||
1 … | +use std::thread; | |
2 … | +use std::sync::mpsc::{channel, Sender, Receiver}; | |
3 … | + | |
4 … | +pub type Time = f32; | |
5 … | + | |
6 … | +pub enum ChangeMode { | |
7 … | + Start, | |
8 … | + Continue, | |
9 … | + Stop | |
10 … | +} | |
11 … | + | |
12 … | +pub | |
13 … | + | |
14 … | + | |
15 … | +pub enum Control { | |
16 … | + Time(Time), | |
17 … | + ChangeMode(ChangeMode), | |
18 … | + TapTempo, | |
19 … | + SetTempo(), | |
20 … | + Nudge( | |
21 … | + Configure(ChangeMode) | |
22 … | +} | |
23 … | + | |
24 … | +pub fn create_control_channel() -> (Sender<Control>, Receiver<Control>) { | |
25 … | + return channel(); | |
26 … | +} | |
27 … | + | |
28 … | +pub fn connect_clock(fps: u32, control_tx: Sender<Control>) { | |
29 … | + thread::spawn(move|| { | |
30 … | + let mut fps_clock = fps_clock::FpsClock::new(fps); | |
31 … | + let mut nanosecs_since_start = 0.0; | |
32 … | + let mut nanosecs_since_last_tick; | |
33 … | + loop { | |
34 … | + nanosecs_since_last_tick = fps_clock.tick(); | |
35 … | + nanosecs_since_start += nanosecs_since_last_tick; | |
36 … | + let clock_time = Control::Time(nanosecs_since_start); | |
37 … | + control_tx.send(clock_time).unwrap(); | |
38 … | + } | |
39 … | + }); | |
40 … | +} |
Built with git-ssb-web