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 std::io::{self, BufWriter};
|
||||||
|
|
||||||
use note::notes::*;
|
use note::notes::*;
|
||||||
use piece::{NoteEvent, Piece};
|
use piece::{NoteEvent, Piece, Track, Wave};
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub fn main() -> io::Result<()> {
|
pub fn crazy_train() -> Piece {
|
||||||
let mut piece = Piece::new(120);
|
let mut piece = Piece::new(120);
|
||||||
|
let mut main_track = Track::new(Wave::Square, 0.1);
|
||||||
let mut time = 0.0;
|
let mut time = 0.0;
|
||||||
|
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(CS4, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(CS4, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(D4, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(D4, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(CS4, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(CS4, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(FS3, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(B4, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(B4, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(GS3, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(GS3, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(B4, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(B4, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
main_track.notes.push(NoteEvent::new(A4, time, 0.5)); time += 0.5;
|
||||||
piece.notes.push(NoteEvent::new(GS3, time, 0.5)); time += 0.5;
|
main_track.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(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 file = File::create("output.wav")?;
|
||||||
let mut writer = BufWriter::new(file);
|
let mut writer = BufWriter::new(file);
|
||||||
piece.generate_wav(&mut writer)?;
|
technology().generate_wav(&mut writer)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
74
src/piece.rs
74
src/piece.rs
@ -3,6 +3,31 @@ use std::io::{self, Write};
|
|||||||
use crate::note::*;
|
use crate::note::*;
|
||||||
use crate::wav;
|
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 struct NoteEvent {
|
||||||
pub note: Note,
|
pub note: Note,
|
||||||
pub start: f64,
|
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>,
|
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,
|
pub bpm: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Piece {
|
impl Piece {
|
||||||
pub fn new(bpm: u32) -> 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<()> {
|
pub fn generate_wav<W: Write>(&self, writer: &mut W) -> io::Result<()> {
|
||||||
@ -35,9 +79,15 @@ impl Piece {
|
|||||||
let params = wav::Params::new();
|
let params = wav::Params::new();
|
||||||
|
|
||||||
let max_beat = self
|
let max_beat = self
|
||||||
.notes
|
.tracks
|
||||||
.iter()
|
.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))
|
.max_by(|x, y| x.total_cmp(y))
|
||||||
.unwrap_or(0.0);
|
.unwrap_or(0.0);
|
||||||
|
|
||||||
@ -55,17 +105,17 @@ impl Piece {
|
|||||||
for i in 0..total_samples {
|
for i in 0..total_samples {
|
||||||
let t = i as f64 / params.sampling_rate as f64;
|
let t = i as f64 / params.sampling_rate as f64;
|
||||||
let mut value: f64 = 0.0;
|
let mut value: f64 = 0.0;
|
||||||
for event in &self.notes {
|
for track in &self.tracks {
|
||||||
let start_time = event.start * seconds_per_beat;
|
for event in &track.notes {
|
||||||
let end_time = start_time + event.duration * seconds_per_beat;
|
let start_time = event.start * seconds_per_beat;
|
||||||
if t >= start_time && t < end_time {
|
let end_time = start_time + event.duration * seconds_per_beat;
|
||||||
let freq = event.note.freq();
|
if t >= start_time && t < end_time {
|
||||||
let sin = (std::f64::consts::TAU * freq * (t - start_time)).sin();
|
value += track.amplitude * track.wave.sample(&event.note, t);
|
||||||
value += if sin >= 0.0 { 1.0 } else { -1.0 };
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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())?;
|
writer.write_all(&sample.to_le_bytes())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user