aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
blob: 0210df88abb69abead23f94ae148951420783640 (plain) (blame)
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
// trriggy - a trigger/drum replacer in Rust
// Copyright (C) 2018  Harald Eilertsen <haraldei@anduin.net>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use hound;
use std::io::Read;
use std::iter::FromIterator;

#[derive(Default)]
struct Trigger {
    trigged: bool,
    playing: bool,
    acc: u32,
    sample_pos: usize,
    sample: Vec<i16>,
}

impl Trigger {
    pub fn new<T: Read>(samples: hound::WavReader<T>) -> Trigger {
        Trigger::default().read_samples(samples)
    }

    fn read_samples<T: Read>(mut self, mut reader: hound::WavReader<T>) -> Trigger {
        self.sample = Vec::from_iter(reader.samples().map(|s| s.unwrap()));
        self
    }

    pub fn process(&mut self, sample: i16) -> i16 {
        let mut res = 0i16;

        let abs = sample.abs() as u32;
        self.acc = (self.acc + abs) / 2;
        if !self.trigged && self.acc > 1000 {
            self.trigged = true;
            self.playing = true;
            self.sample_pos = 0;
        }
        else if self.trigged && self.acc < 50 {
            self.trigged = false;
        }

        if self.playing {
            res = self.sample[self.sample_pos];
            self.sample_pos += 1;
        }

        if self.sample_pos > self.sample.len() {
            self.playing = false;
        }

        res
    }
}

fn print_wavspec<R: Read>(spec: &hound::WavSpec, r: &hound::WavReader<R>) {
    println!("  channels: {}", spec.channels);
    println!("  samplerate: {}", spec.sample_rate);
    println!("  bits/sample: {}", spec.bits_per_sample);
    println!("  sample format: {}", match spec.sample_format {
        hound::SampleFormat::Int => "integer",
        hound::SampleFormat::Float => "floating point",
    });
    println!("  duration: {} samples/{} sec/{} min",
        r.duration(),
        r.duration()/spec.sample_rate,
        r.duration()/(spec.sample_rate * 60));
}

fn main() {
    let filename = "test.wav";
    let mut reader = hound::WavReader::open(&filename).unwrap();

    println!("Reading file {}:", &filename);

    let spec = reader.spec();
    print_wavspec(&spec, &reader);

    println!("Using sample file: {}", "bd.wav");
    let mut sample_file = hound::WavReader::open("bd.wav").unwrap();

    print_wavspec(&sample_file.spec(), &sample_file);

    println!("Writing to output: {}", "output.wav");
    let mut output = hound::WavWriter::create("output.wav", spec).unwrap();

    let samples = reader.samples::<i16>();
    let mut triggey = Trigger::new(sample_file);

    samples
        .map(|s| s.unwrap())
        .for_each(|s| {
            output.write_sample(triggey.process(s)).unwrap();
        });

    output.finalize().unwrap();
}