summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 4f6089e50cd8f2b406d41bd05c1495511b038195 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// @TODO: sort presets alphabetically
extern crate cpal;

use std::io::Write;

use cpal::traits::{HostTrait, DeviceTrait, StreamTrait};

mod midi_input;
mod soundfont;

#[allow(unused)]
fn playmidi_main() -> Result<(), String> {
	let mut device_mgr = midi_input::DeviceManager::new()?;
	device_mgr.set_quiet(true);
	let devices = device_mgr.list()?;
	for (index, device) in (&devices).into_iter().enumerate() {
		print!("{:3} | ", index + 1);
		let mut first = true;
		for line in device.name.lines() {
			if !first {
				print!("    | ");
			}
			println!("{}", line);
			first = false;
		}
		println!("    -----------------");
	}
	print!("Select a device (default {}): ", devices.default + 1);
	if std::io::stdout().flush().is_err() {
		//who cares
	}

	let device_id;
	{
		let mut buf = String::new();
		std::io::stdin()
			.read_line(&mut buf)
			.expect("error reading stdin");
		let s = buf.trim();
		if s.is_empty() {
			device_id = &devices[devices.default].id;
		} else {
			match s.parse::<usize>() {
				Ok(idx) if idx >= 1 && idx <= devices.len() => {
					device_id = &devices[idx - 1].id;
				}
				_ => {
					return Err(format!("Bad device ID: {}", s));
				}
			}
		}
	}
	let mut device = device_mgr
		.open(device_id)
		.expect("error opening MIDI device");

	while device.is_connected() {
		let maybe_event = device.read_event();
		if let Some(event) = maybe_event {
			println!("{:?}", event);
		} else {
			std::thread::sleep(std::time::Duration::from_millis(10));
		}
		if let Some(err) = device.get_error() {
			eprintln!("Error: {}", err);
			device.clear_error();
		}
	}
	Ok(())
}

fn main() {
	let mut sf = match soundfont::SoundFont::open("/etc/alternatives/default-GM.sf2") {
		Err(x) => {
			eprintln!("Error: {}", String::from(x));
			return;
		}
		Ok(s) => s,
	};

	 	for i in 0..sf.preset_count() {
	 		println!("{}. {}", i, sf.preset_name(i).unwrap());
	 	}

	// 	let result = playmidi_main();
	// 	if let Err(s) = result {
	// 		eprintln!("Error: {}", s);
	// 	}
	let host = cpal::default_host();
	let device = host.default_output_device().expect("no output device available");
	let supported_configs = device.supported_output_configs()
		.expect("error while querying configs");
	let mut chosen_config = None;
	for config in supported_configs {
		if config.channels() != 2 || config.sample_format() != cpal::SampleFormat::I16 {
			continue;
		}
		chosen_config = Some(config);
	}
	let chosen_config = match chosen_config {
		None => {
			eprintln!("Couldn't configure audio device to have 2 16-bit channels.");
			return;
		},
		Some(x) => x,
	};
	let supp_config: cpal::SupportedStreamConfig = chosen_config
		.with_max_sample_rate()
		.into();
	if supp_config.channels() != 2 {
	}
	let config = supp_config.into();
	let mut time = 0.0;
	let mut key = 60;
	let stream = device.build_output_stream(
		&config,
		move |data: &mut [i16], _: &cpal::OutputCallbackInfo| {
			for x in data.iter_mut() {
				*x = 0;
			}
			let sample_rate = config.sample_rate.0 as f64;
			match sf.add_samples_interlaced(126, 1.0, key, 60, time, data, sample_rate) {
				Ok(false) => {println!("stop")},
				Err(e) => eprintln!("{}", e),
				_ => {},
			}
			time += (data.len() as f64) / (2.0 * sample_rate);
			if time >= 1.0 {
				time = 0.0;
				key += 1;
			}
		},
		move |err| {
			println!("audio stream error: {}", err);
		},
	).expect("couldn't build output stream");
	stream.play().expect("couldn't play stream");

	loop {
		std::thread::sleep(std::time::Duration::from_millis(100));
	}
}