Tracks
This commit is contained in:
parent
99b9a79d5e
commit
eed4a3494d
136
src/lib.rs
136
src/lib.rs
@ -6,37 +6,133 @@ use std::fs::File;
|
||||
use std::io::{self, BufWriter};
|
||||
|
||||
use note::notes::*;
|
||||
use piece::{NoteEvent, Piece};
|
||||
use piece::{NoteEvent, Piece, Track, Wave};
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub fn main() -> io::Result<()> {
|
||||
pub fn crazy_train() -> Piece {
|
||||
let mut piece = Piece::new(120);
|
||||
let mut main_track = Track::new(Wave::Square, 0.1);
|
||||
let mut time = 0.0;
|
||||
|
||||
for _ in 0..4 {
|
||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(CS4, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(D4, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(CS4, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(B4, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(GS3, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(B4, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(GS3, time, 0.5)); time += 0.5;
|
||||
piece.notes.push(NoteEvent::new(E3, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(CS4, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(D4, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(CS4, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(B4, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(GS3, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(B4, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(GS3, time, 0.5)); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 0.5)); time += 0.5;
|
||||
}
|
||||
|
||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5));
|
||||
main_track.notes.push(NoteEvent::new(FS3, time, 0.5));
|
||||
|
||||
piece.tracks.push(main_track);
|
||||
piece
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub fn technology() -> Piece {
|
||||
let mut piece = Piece::new(100);
|
||||
|
||||
let mut bass_track = Track::new(Wave::Square, 0.05);
|
||||
let mut time = 0.0;
|
||||
for _ in 0..2 {
|
||||
bass_track.notes.push(NoteEvent::new(A1, time, 4.0)); time += 4.0;
|
||||
bass_track.notes.push(NoteEvent::new(G0, time, 2.0)); time += 2.0;
|
||||
bass_track.notes.push(NoteEvent::new(A1, time, 2.0)); time += 2.0;
|
||||
|
||||
bass_track.notes.push(NoteEvent::new(F0, time, 4.0)); time += 4.0;
|
||||
bass_track.notes.push(NoteEvent::new(C1, time, 2.0)); time += 2.0;
|
||||
bass_track.notes.push(NoteEvent::new(G0, time, 2.0)); time += 2.0;
|
||||
}
|
||||
piece.tracks.push(bass_track);
|
||||
|
||||
let mut main_track = Track::new(Wave::Square, 0.1);
|
||||
let mut time = 0.0;
|
||||
|
||||
// Lick 1
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(G3, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(G3, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 1.0 )); time += 1.0;
|
||||
|
||||
time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 1.0 )); time += 1.0;
|
||||
main_track.notes.push(NoteEvent::new(G3, time, 1.0 )); time += 1.0;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(F3, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(D3, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 0.5 )); time += 0.5;
|
||||
|
||||
main_track.notes.push(NoteEvent::new(C3, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 1.0 )); time += 1.0;
|
||||
main_track.notes.push(NoteEvent::new(C3, time, 0.33)); time += 0.33;
|
||||
main_track.notes.push(NoteEvent::new(D3, time, 0.42)); time += 0.42;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 1.75)); time += 1.75;
|
||||
|
||||
main_track.notes.push(NoteEvent::new(C3, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 1.0 )); time += 1.0;
|
||||
main_track.notes.push(NoteEvent::new(C3, time, 0.33)); time += 0.33;
|
||||
main_track.notes.push(NoteEvent::new(E2, time, 0.42)); time += 0.42;
|
||||
main_track.notes.push(NoteEvent::new(D2, time, 1.5 )); time += 1.5;
|
||||
|
||||
main_track.notes.push(NoteEvent::new(G2, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(C3, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(G3, time, 0.25)); time += 0.25;
|
||||
|
||||
// Lick 2
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(G3, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(G3, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 1.0 )); time += 1.0;
|
||||
|
||||
time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 1.0 )); time += 1.0;
|
||||
main_track.notes.push(NoteEvent::new(G3, time, 1.0 )); time += 1.0;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(B4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(C4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(B4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(A4, time, 0.25)); time += 0.25;
|
||||
main_track.notes.push(NoteEvent::new(B4, time, 0.5 )); time += 0.5;
|
||||
|
||||
main_track.notes.push(NoteEvent::new(C3, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 1.0 )); time += 1.0;
|
||||
main_track.notes.push(NoteEvent::new(C3, time, 0.33)); time += 0.33;
|
||||
main_track.notes.push(NoteEvent::new(D3, time, 0.42)); time += 0.42;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 1.75)); time += 1.75;
|
||||
|
||||
main_track.notes.push(NoteEvent::new(C3, time, 0.5 )); time += 0.5;
|
||||
main_track.notes.push(NoteEvent::new(E3, time, 1.0 )); time += 1.0;
|
||||
main_track.notes.push(NoteEvent::new(C3, time, 0.33)); time += 0.33;
|
||||
main_track.notes.push(NoteEvent::new(A3, time, 0.42)); time += 0.42;
|
||||
main_track.notes.push(NoteEvent::new(G2, time, 2.25)); time += 2.25;
|
||||
piece.tracks.push(main_track);
|
||||
|
||||
piece
|
||||
}
|
||||
|
||||
pub fn main() -> io::Result<()> {
|
||||
let file = File::create("output.wav")?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
piece.generate_wav(&mut writer)?;
|
||||
technology().generate_wav(&mut writer)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
74
src/piece.rs
74
src/piece.rs
@ -3,6 +3,31 @@ use std::io::{self, Write};
|
||||
use crate::note::*;
|
||||
use crate::wav;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Wave {
|
||||
Square,
|
||||
Triangle,
|
||||
}
|
||||
|
||||
impl Wave {
|
||||
pub fn sample(self, note: &Note, t: f64) -> f64 {
|
||||
let freq = note.freq();
|
||||
match self {
|
||||
Wave::Square => {
|
||||
if (2.0 * std::f64::consts::PI * freq * t).sin() >= 0.0 {
|
||||
1.0
|
||||
} else {
|
||||
-1.0
|
||||
}
|
||||
}
|
||||
Wave::Triangle => {
|
||||
let phase = (freq * t) % 1.0;
|
||||
4.0 * (phase - 0.5).abs() - 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NoteEvent {
|
||||
pub note: Note,
|
||||
pub start: f64,
|
||||
@ -19,14 +44,33 @@ impl NoteEvent {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Piece {
|
||||
pub struct Track {
|
||||
pub wave: Wave,
|
||||
pub amplitude: f64,
|
||||
pub notes: Vec<NoteEvent>,
|
||||
}
|
||||
|
||||
impl Track {
|
||||
pub fn new(wave: Wave, amplitude: f64) -> Track {
|
||||
Track {
|
||||
wave,
|
||||
amplitude,
|
||||
notes: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Piece {
|
||||
pub tracks: Vec<Track>,
|
||||
pub bpm: u32,
|
||||
}
|
||||
|
||||
impl Piece {
|
||||
pub fn new(bpm: u32) -> Piece {
|
||||
Piece { bpm, notes: vec![] }
|
||||
Piece {
|
||||
bpm,
|
||||
tracks: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_wav<W: Write>(&self, writer: &mut W) -> io::Result<()> {
|
||||
@ -35,9 +79,15 @@ impl Piece {
|
||||
let params = wav::Params::new();
|
||||
|
||||
let max_beat = self
|
||||
.notes
|
||||
.tracks
|
||||
.iter()
|
||||
.map(|x| x.start + x.duration)
|
||||
.map(|x| {
|
||||
x.notes
|
||||
.iter()
|
||||
.map(|x| x.start + x.duration)
|
||||
.max_by(|x, y| x.total_cmp(y))
|
||||
.unwrap_or(0.0)
|
||||
})
|
||||
.max_by(|x, y| x.total_cmp(y))
|
||||
.unwrap_or(0.0);
|
||||
|
||||
@ -55,17 +105,17 @@ impl Piece {
|
||||
for i in 0..total_samples {
|
||||
let t = i as f64 / params.sampling_rate as f64;
|
||||
let mut value: f64 = 0.0;
|
||||
for event in &self.notes {
|
||||
let start_time = event.start * seconds_per_beat;
|
||||
let end_time = start_time + event.duration * seconds_per_beat;
|
||||
if t >= start_time && t < end_time {
|
||||
let freq = event.note.freq();
|
||||
let sin = (std::f64::consts::TAU * freq * (t - start_time)).sin();
|
||||
value += if sin >= 0.0 { 1.0 } else { -1.0 };
|
||||
for track in &self.tracks {
|
||||
for event in &track.notes {
|
||||
let start_time = event.start * seconds_per_beat;
|
||||
let end_time = start_time + event.duration * seconds_per_beat;
|
||||
if t >= start_time && t < end_time {
|
||||
value += track.amplitude * track.wave.sample(&event.note, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let sample = (value * (i16::MAX as f64) * amplitude).round() as i16;
|
||||
let sample = (value * (i16::MAX as f64)).round() as i16;
|
||||
writer.write_all(&sample.to_le_bytes())?;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user