//! Example of creating a ptvoice from scratch. #![allow(unused)] use ptcrab::data::WriteTo; use ptcrab::ptvoice::{PtvEnvelope, PtvUnit, PtvWave, Ptvoice}; use ptcrab::{Key, Tuning, Volume}; use anyhow::Result as AnyResult; use std::env::args; use std::f32::consts::TAU; use std::fs::File; //-------------------------------------------------------------------------------------------------- fn main() -> AnyResult<()> { // Create a `PtvWave` that defines a ptvoice unit's waveform. //---------------------------------------------------------------------------------------------- // Coordinate points can be manually specified... let wave_saw = PtvWave::coordinate_from_points(Box::new([(0, 0), (0, 64), (255, -64)])); // ... or generated by a function over 0 ≤ x < 1 (in this case sine cubed). let wave_sine3 = PtvWave::coordinate_from_function(31, |x| (x * TAU).sin().powi(3)); // Oscillator `(harmonic_num, amplitude)` pairs must be manually specified. let wave_osc = PtvWave::oscillator_from_pairs(Box::new([ (1, 128), // 1st harmonic with 128 amplitude. (2, -64), // 2nd harmonic with 64 amplitude, inverted. (4, 32), // 4th harmonic with 32 amplitude. ])); // Create a `PtvEnvelope` that controls a unit's volume over time. //---------------------------------------------------------------------------------------------- // An envelope with 100ms attack and 50ms release. let envelope_attack = PtvEnvelope::new(Box::new([(100, 128)]), 50); // An envelope that creates a 160ms pulse after 80ms. let envelope_pulse = PtvEnvelope::new(Box::new([(79, 0), (80, 128), (240, 128), (241, 0)]), 1); // Create `PtvUnit`s with the desired parameters, waveforms, and envelopes. //---------------------------------------------------------------------------------------------- let unit_1 = PtvUnit { // Slightly detune this unit. tuning: 0.9995.into(), wave: Some(wave_sine3), envelope: Some(envelope_attack), ..Default::default() }; let unit_2 = PtvUnit { // Make this unit quieter than default (64). volume: 32.into(), wave: Some(wave_osc), envelope: Some(envelope_pulse), ..Default::default() }; //---------------------------------------------------------------------------------------------- // Finally, construct the ptvoice from the two units. let ptv = Ptvoice::new(Box::new([unit_1, unit_2])); // If a filename was given, write the ptvoice to the output file. Otherwise, just print it. if let Some(filename) = args().nth(1) { let mut file = File::create(filename)?; ptv.write_to(&mut file)?; } else { println!("{:?}", ptv); } Ok(()) }