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