steamy-controller 0.2.1

Library to interact with the Steam controller.
Documentation
use std::io::Write;
use std::time::Duration;
use byteorder::{WriteBytesExt, LittleEndian};
use {Result as Res, Controller};

const RATIO:       f64        = 495483.0;
const FREQUENCIES: [f64; 128] = [8.1758, 8.66196, 9.17702, 9.72272, 10.3009, 10.9134, 11.5623, 12.2499, 12.9783, 13.75, 14.5676, 15.4339, 16.3516, 17.3239, 18.354, 19.4454, 20.6017, 21.8268, 23.1247, 24.4997, 25.9565, 27.5, 29.1352, 30.8677, 32.7032, 34.6478, 36.7081, 38.8909, 41.2034, 43.6535, 46.2493, 48.9994, 51.9131, 55.0, 58.2705, 61.7354, 65.4064, 69.2957, 73.4162, 77.7817, 82.4069, 87.3071, 92.4986, 97.9989, 103.826, 110.0, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220.0, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440.0, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880.0, 932.328, 987.767, 1046.5, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760.0, 1864.66, 1975.53, 2093.0, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520.0, 3729.31, 3951.07, 4186.01, 4434.92, 4698.64, 4978.03, 5274.04, 5587.65, 5919.91, 6271.93, 6644.88, 7040.0, 7458.62, 7902.13, 8372.02, 8869.84, 9397.27, 9956.06, 10548.1, 11175.3, 11839.8, 12543.9];

/// Representation of a note.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Note {
	A,
	B,
	C,
	D,
	E,
	F,
	G,
}

pub struct Sound<'a, 'b: 'a> {
	controller: &'a mut Controller<'b>,
	channel:    u8,
	note:       Note,
	sharp:      bool,
	octave:     u8,
	duration:   f64,
}

impl<'a, 'b> Sound<'a, 'b> {
	#[doc(hidden)]
	pub fn new(controller: &'a mut Controller<'b>) -> Sound<'a, 'b> {
		Sound {
			controller: controller,
			channel:    0,
			note:       Note::C,
			sharp:      false,
			octave:     6,
			duration:   -1.0,
		}
	}

	/// Test a notification sound.
	pub fn test(self, value: u8) -> Res<()> {
		self.controller.control_with(0xb6, 0x04, |mut buf| {
			buf.write_u8(value)
		})
	}

	/// Change the notification sound when turning on and off the device.
	pub fn notification(self, on: u8, off: u8) -> Res<()> {
		self.controller.control_with(0xc1, 0x10, |mut buf| {
			try!(buf.write_u8(on));
			try!(buf.write_u8(off));

			buf.write(&[
				0xff, 0xff, 0x03, 0x09,
				0x05, 0xff, 0xff, 0xff,
				0xff, 0xff, 0xff, 0xff,
				0xff, 0xff
			][..])
		})
	}

	/// Send the sound on the left channel.
	pub fn left(mut self) -> Self {
		self.channel = 1;
		self
	}

	/// Send the sound on the right channel.
	pub fn right(mut self) -> Self {
		self.channel = 0;
		self
	}

	/// The note to reproduce.
	pub fn note(mut self, value: Note) -> Self {
		self.note = value;
		self
	}

	/// Whether it's a sharp.
	pub fn sharp(mut self) -> Self {
		self.sharp = true;
		self
	}

	/// The octave.
	pub fn octave(mut self, value: u8) -> Self {
		self.octave = value;
		self
	}

	/// The duration of the note.
	pub fn duration(mut self, value: Duration) -> Self {
		self.duration = value.as_secs() as f64 + (value.subsec_nanos() as f64 / 1_000_000_000.0);
		self
	}

	/// Play the note.
	pub fn play(self) -> Res<()> {
		let index = match self.note {
			Note::C => if self.sharp { 1 } else { 0 },
			Note::D => if self.sharp { 3 } else { 2 },
			Note::E => 4,
			Note::F => if self.sharp { 6 } else { 5 },
			Note::G => if self.sharp { 8 } else { 7 },
			Note::A => if self.sharp { 10 } else { 9 },
			Note::B => 11,
		} + (self.octave * 12) as usize;

		let channel  = self.channel;
		let duration = self.duration;
		let period   = 1.0 / FREQUENCIES[if index >= 128 { 127 } else { index }];

		self.controller.control_with(0x8f, 0x07, |mut buf| {
			try!(buf.write_u8(channel));

			try!(buf.write_u16::<LittleEndian>((period * RATIO).round() as u16));
			try!(buf.write_u16::<LittleEndian>((period * RATIO).round() as u16));

			if duration >= 0.0 {
				try!(buf.write_u16::<LittleEndian>((duration / period).round() as u16));
			}
			else {
				try!(buf.write_u16::<LittleEndian>(0x7fff));
			}

			Ok(())
		})
	}

	/// Stop playing.
	pub fn stop(self) -> Res<()> {
		let channel = self.channel;

		self.controller.control_with(0x8f, 0x07, |mut buf| {
			buf.write_u8(channel)
		})
	}
}