1 // Copyright (C) 2020 Natanael Mojica <neithanmo@gmail.com>
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU Library General Public
14 // License along with this library; if not, write to the
15 // Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
16 // Boston, MA 02110-1335, USA.
17 
18 use gst::prelude::*;
19 
20 use std::error::Error;
21 
22 const AUDIO_SRC: &str = "audiotestsrc";
23 const AUDIO_SINK: &str = "audioconvert ! autoaudiosink";
24 
25 // This example defines two instruments, the first instrument send to the output that is at its input and accumulates the received audio samples
26 // into a global variable called gasig. The execution of this instrument last the first 2 seconds.
27 // The second instrument starts it execution at 1.8 second, This instrument creates two audio buffers with samples that are read
28 // from the global accumulator(gasig), then reads these buffers at a fixed delay time, creating the adelL, adelM and adelR buffers,
29 // also, It multiplies the audio samples in the right channel by 0.5 * kdel, being kdel a line of values starting at 0.5 at increments of 0.001.
30 // Finally, those buffers are mixed with the accumulator, and an audio envelop is applied(aseg) to them.
31 // The result is similar to an audio echo in which the buffered samples are read at different delay times and also modified in frecuency(right channel),
32 // this creates an space effect using just one channel audio input.
33 const CSD: &str = "
34     <CsoundSynthesizer>
35     <CsOptions>
36     </CsOptions>
37     <CsInstruments>
38 
39     sr = 44100
40     ksmps = 7
41 
42     nchnls_i = 1
43     nchnls = 2
44 
45     gasig  init 0
46     gidel  = 1
47 
48     instr 1
49 
50         ain in
51             outs ain, ain
52 
53         vincr gasig, ain
54     endin
55 
56     instr 2
57 
58         ifeedback = p4
59 
60         aseg linseg 1., p3, 0.0
61 
62         abuf2	delayr	gidel
63         adelL 	deltap	.4
64         adelM 	deltap	.5
65             delayw	gasig + (adelL * ifeedback)
66 
67         abuf3	delayr	gidel
68         kdel	line    .5, p3, .001
69         adelR 	deltap  .5 * kdel
70             delayw	gasig + (adelR * ifeedback)
71     	outs	(adelL + adelM) * aseg, (adelR + adelM) * aseg
72         clear	gasig
73     endin
74 
75     </CsInstruments>
76     <CsScore>
77 
78     i 1 0 2
79     i 2 1.8 5 .8
80     e
81     </CsScore>
82     </CsoundSynthesizer>";
83 
create_pipeline() -> Result<gst::Pipeline, Box<dyn Error>>84 fn create_pipeline() -> Result<gst::Pipeline, Box<dyn Error>> {
85     let pipeline = gst::Pipeline::new(None);
86 
87     let audio_src = gst::parse_bin_from_description(AUDIO_SRC, true)?.upcast();
88 
89     let audio_sink = gst::parse_bin_from_description(AUDIO_SINK, true)?.upcast();
90 
91     let csoundfilter = gst::ElementFactory::make("csoundfilter", None)?;
92     csoundfilter.set_property("csd-text", &CSD)?;
93 
94     pipeline.add_many(&[&audio_src, &csoundfilter, &audio_sink])?;
95 
96     audio_src.link_pads(Some("src"), &csoundfilter, Some("sink"))?;
97     csoundfilter.link_pads(Some("src"), &audio_sink, Some("sink"))?;
98 
99     Ok(pipeline)
100 }
101 
main_loop(pipeline: gst::Pipeline) -> Result<(), Box<dyn Error>>102 fn main_loop(pipeline: gst::Pipeline) -> Result<(), Box<dyn Error>> {
103     pipeline.set_state(gst::State::Playing)?;
104 
105     let bus = pipeline
106         .bus()
107         .expect("Pipeline without bus. Shouldn't happen!");
108 
109     for msg in bus.iter_timed(gst::ClockTime::NONE) {
110         use gst::MessageView;
111 
112         match msg.view() {
113             MessageView::Eos(..) => break,
114             MessageView::Error(err) => {
115                 println!(
116                     "Error from {:?}: {} ({:?})",
117                     msg.src().map(|s| s.path_string()),
118                     err.error(),
119                     err.debug()
120                 );
121                 break;
122             }
123             _ => (),
124         }
125     }
126 
127     pipeline.set_state(gst::State::Null)?;
128 
129     Ok(())
130 }
131 
main() -> Result<(), Box<dyn Error>>132 fn main() -> Result<(), Box<dyn Error>> {
133     gst::init().unwrap();
134 
135     gstcsound::plugin_register_static().expect("Failed to register csound plugin");
136 
137     create_pipeline().and_then(main_loop)
138 }
139