megra_rs 0.0.6

A live-coding language with Markov chains.
use std::collections::HashMap;

use crate::builtin_types::*;
use crate::parameter::*;

use std::collections::BTreeSet;

use ruffbox_synth::building_blocks::SynthParameterLabel;

use crate::parser::{BuiltIn, EvaluatedExpr, FunctionMap};
use crate::{OutputMode, SampleAndWavematrixSet};
use parking_lot::Mutex;
use std::sync;

pub fn load_part(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    let mut gens = Vec::new();
    let mut proxies = Vec::new();

    let name: String = if let Some(EvaluatedExpr::Symbol(s)) = tail_drain.next() {
        s
    } else {
        return None;
    };

    for c in tail_drain {
        match c {
            EvaluatedExpr::BuiltIn(BuiltIn::Generator(g)) => gens.push(g),
            EvaluatedExpr::BuiltIn(BuiltIn::GeneratorList(mut gl)) => gens.append(&mut gl),
            EvaluatedExpr::BuiltIn(BuiltIn::PartProxy(p)) => proxies.push(p),
            EvaluatedExpr::BuiltIn(BuiltIn::ProxyList(mut pl)) => proxies.append(&mut pl),
            _ => {}
        }
    }

    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(Command::LoadPart(
        (name, Part::Combined(gens, proxies)),
    ))))
}

pub fn define_midi_callback(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);

    let key: u8 = if let Some(EvaluatedExpr::Float(s)) = tail_drain.next() {
        s as u8
    } else {
        return None;
    };

    if let Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(c))) = tail_drain.next() {
        Some(EvaluatedExpr::BuiltIn(BuiltIn::DefineMidiCallback(key, c)))
    } else {
        None
    }
}

#[allow(clippy::unnecessary_unwrap)]
pub fn load_sample_as_wavematrix(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);

    let mut key: Option<String> = None;
    let mut path: Option<String> = None;
    let mut method: Option<String> = Some("zerocrossing_fixed_stretch_inverse".to_string());
    let mut matrix_size: Option<(usize, usize)> = None;
    let mut start: Option<f32> = Some(0.0);

    while let Some(c) = tail_drain.next() {
        if let EvaluatedExpr::Keyword(k) = c {
            if k.as_str() == "key" {
                // default is zero ...
                if let Some(EvaluatedExpr::Symbol(n)) = tail_drain.next() {
                    key = Some(n);
                }
            }
            if k.as_str() == "start" {
                // default is zero ...
                if let Some(EvaluatedExpr::Float(f)) = tail_drain.next() {
                    start = Some(f);
                }
            }
            if k.as_str() == "path" {
                // default is zero ...
                if let Some(EvaluatedExpr::String(s)) = tail_drain.next() {
                    path = Some(s);
                }
            }
            if k.as_str() == "method" {
                // default is zero ...
                if let Some(EvaluatedExpr::Symbol(s)) = tail_drain.next() {
                    method = Some(s);
                }
            }
            if k.as_str() == "size" {
                // default is zero ...
                if let Some(EvaluatedExpr::Float(x)) = tail_drain.next() {
                    if let Some(EvaluatedExpr::Float(y)) = tail_drain.next() {
                        matrix_size = Some((x as usize, y as usize));
                    }
                }
            }
        }
    }
    if key.is_some() && path.is_some() && matrix_size.is_some() {
        Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
            Command::LoadSampleAsWavematrix(
                key.unwrap(),
                path.unwrap(),
                method.unwrap(),
                matrix_size.unwrap(),
                start.unwrap(),
            ),
        )))
    } else {
        None
    }
}

pub fn freeze_buffer(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);

    // on the user side,
    // both input- and freeze buffers are counted
    // starting at 1
    let mut inbuf: usize = 0;
    let mut freezbuf: usize = 0;

    while let Some(c) = tail_drain.next() {
        match c {
            EvaluatedExpr::Keyword(k) => {
                if k.as_str() == "in" {
                    // default is zero ...
                    if let Some(EvaluatedExpr::Float(n)) = tail_drain.next() {
                        if n as usize > 0 {
                            inbuf = n as usize - 1;
                        }
                    }
                }
            }
            EvaluatedExpr::Float(f) => {
                if f as usize > 0 {
                    freezbuf = f as usize - 1;
                }
            }
            _ => {}
        }
    }

    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::FreezeBuffer(freezbuf, inbuf),
    )))
}

pub fn load_sample(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);

    let mut collect_keywords = false;

    let mut keywords: Vec<String> = Vec::new();
    let mut path: String = "".to_string();
    let mut set: String = "".to_string();

    while let Some(c) = tail_drain.next() {
        if collect_keywords {
            if let EvaluatedExpr::Symbol(ref s) = c {
                keywords.push(s.to_string());
                continue;
            } else {
                collect_keywords = false;
            }
        }

        if let EvaluatedExpr::Keyword(k) = c {
            match k.as_str() {
                "keywords" => {
                    collect_keywords = true;
                    continue;
                }
                "set" => {
                    if let Some(EvaluatedExpr::Symbol(n)) = tail_drain.next() {
                        set = n.to_string();
                    }
                }
                "path" => {
                    if let Some(EvaluatedExpr::String(n)) = tail_drain.next() {
                        path = n.to_string();
                    }
                }
                _ => println!("{}", k),
            }
        }
    }

    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::LoadSample((set, keywords, path)),
    )))
}

pub fn load_sample_sets(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    let path = if let EvaluatedExpr::String(n) = tail_drain.next().unwrap() {
        n
    } else {
        "".to_string()
    };

    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::LoadSampleSets(path),
    )))
}

pub fn load_sample_set(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    let path = if let EvaluatedExpr::String(n) = tail_drain.next().unwrap() {
        n
    } else {
        "".to_string()
    };

    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::LoadSampleSet(path),
    )))
}

pub fn tmod(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(Command::Tmod(
        match tail_drain.next() {
            Some(EvaluatedExpr::BuiltIn(BuiltIn::Parameter(p))) => p,
            Some(EvaluatedExpr::Float(f)) => DynVal::with_value(f),
            _ => DynVal::with_value(1.0),
        },
    ))))
}

pub fn latency(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(Command::Latency(
        match tail_drain.next() {
            Some(EvaluatedExpr::BuiltIn(BuiltIn::Parameter(p))) => p,
            Some(EvaluatedExpr::Float(f)) => DynVal::with_value(f),
            _ => DynVal::with_value(0.05),
        },
    ))))
}

pub fn bpm(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(Command::Bpm(
        match tail_drain.next() {
            Some(EvaluatedExpr::Float(f)) => 60000.0 / f,
            _ => 200.0,
        },
    ))))
}

pub fn default_duration(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::DefaultDuration(match tail_drain.next() {
            Some(EvaluatedExpr::Float(f)) => f,
            _ => 200.0,
        }),
    )))
}

pub fn globres(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(Command::GlobRes(
        match tail_drain.next() {
            Some(EvaluatedExpr::Float(f)) => f,
            _ => 400000.0,
        },
    ))))
}

pub fn reverb(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    let mut param_map = HashMap::new();

    while let Some(c) = tail_drain.next() {
        match c {
            EvaluatedExpr::Keyword(k) => match k.as_str() {
                "damp" => {
                    if let Some(EvaluatedExpr::Float(f)) = tail_drain.next() {
                        param_map.insert(
                            SynthParameterLabel::ReverbDampening,
                            ParameterValue::Scalar(DynVal::with_value(f)),
                        );
                    }
                }
                "mix" => {
                    if let Some(EvaluatedExpr::Float(f)) = tail_drain.next() {
                        param_map.insert(
                            SynthParameterLabel::ReverbMix,
                            ParameterValue::Scalar(DynVal::with_value(f.clamp(0.01, 0.99))),
                        );
                    }
                }
                "roomsize" => {
                    if let Some(EvaluatedExpr::Float(f)) = tail_drain.next() {
                        param_map.insert(
                            SynthParameterLabel::ReverbRoomsize,
                            ParameterValue::Scalar(DynVal::with_value(f.clamp(0.01, 0.99))),
                        );
                    }
                }

                _ => println!("{}", k),
            },
            _ => println! {"ignored"},
        }
    }

    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::GlobalRuffboxParams(param_map),
    )))
}

pub fn delay(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    let mut param_map = HashMap::new();

    while let Some(c) = tail_drain.next() {
        match c {
            EvaluatedExpr::Keyword(k) => match k.as_str() {
                "damp-freq" => match tail_drain.next() {
                    Some(EvaluatedExpr::Float(f)) => {
                        param_map.insert(
                            SynthParameterLabel::DelayDampeningFrequency,
                            ParameterValue::Scalar(DynVal::with_value(f.clamp(20.0, 18000.0))),
                        );
                    }
                    Some(EvaluatedExpr::BuiltIn(BuiltIn::Parameter(p))) => {
                        param_map.insert(
                            SynthParameterLabel::DelayDampeningFrequency,
                            ParameterValue::Scalar(p),
                        );
                    }
                    Some(EvaluatedExpr::BuiltIn(BuiltIn::Modulator(m))) => {
                        param_map.insert(SynthParameterLabel::DelayDampeningFrequency, m);
                    }
                    _ => {}
                },
                "feedback" | "fb" => match tail_drain.next() {
                    Some(EvaluatedExpr::Float(f)) => {
                        param_map.insert(
                            SynthParameterLabel::DelayFeedback,
                            ParameterValue::Scalar(DynVal::with_value(f.clamp(0.01, 0.99))),
                        );
                    }
                    Some(EvaluatedExpr::BuiltIn(BuiltIn::Parameter(p))) => {
                        param_map.insert(
                            SynthParameterLabel::DelayFeedback,
                            ParameterValue::Scalar(p),
                        );
                    }
                    Some(EvaluatedExpr::BuiltIn(BuiltIn::Modulator(m))) => {
                        param_map.insert(SynthParameterLabel::DelayFeedback, m);
                    }
                    _ => {}
                },
                "mix" => {
                    if let Some(EvaluatedExpr::Float(f)) = tail_drain.next() {
                        param_map.insert(
                            SynthParameterLabel::DelayMix,
                            ParameterValue::Scalar(DynVal::with_value(f.clamp(0.01, 0.99))),
                        );
                    }
                }
                "time" | "t" => match tail_drain.next() {
                    Some(EvaluatedExpr::Float(f)) => {
                        param_map.insert(
                            SynthParameterLabel::DelayTime,
                            ParameterValue::Scalar(DynVal::with_value(
                                (f / 1000.0).clamp(0.01, 1.99),
                            )),
                        );
                    }
                    Some(EvaluatedExpr::BuiltIn(BuiltIn::Parameter(p))) => {
                        param_map.insert(SynthParameterLabel::DelayTime, ParameterValue::Scalar(p));
                    }
                    Some(EvaluatedExpr::BuiltIn(BuiltIn::Modulator(m))) => {
                        param_map.insert(SynthParameterLabel::DelayTime, m);
                    }
                    _ => {}
                },
                "rate" | "r" => match tail_drain.next() {
                    Some(EvaluatedExpr::Float(f)) => {
                        param_map.insert(
                            SynthParameterLabel::DelayRate,
                            ParameterValue::Scalar(DynVal::with_value(
                                (f / 1000.0).clamp(0.01, 1.99),
                            )),
                        );
                    }
                    Some(EvaluatedExpr::BuiltIn(BuiltIn::Parameter(p))) => {
                        param_map.insert(SynthParameterLabel::DelayRate, ParameterValue::Scalar(p));
                    }
                    Some(EvaluatedExpr::BuiltIn(BuiltIn::Modulator(m))) => {
                        param_map.insert(SynthParameterLabel::DelayRate, m);
                    }
                    _ => {}
                },
                _ => println!("{}", k),
            },
            _ => println! {"ignored"},
        }
    }

    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::GlobalRuffboxParams(param_map),
    )))
}

pub fn export_dot(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);

    // filename
    let filename = if let Some(EvaluatedExpr::String(s)) = tail_drain.next() {
        s
    } else {
        return None;
    };

    match tail_drain.next() {
        Some(EvaluatedExpr::BuiltIn(BuiltIn::Generator(g))) => Some(EvaluatedExpr::BuiltIn(
            BuiltIn::Command(Command::ExportDotStatic((filename, g))),
        )),
        Some(EvaluatedExpr::Keyword(k)) => {
            match k.as_str() {
                "part" => {
                    if let Some(EvaluatedExpr::Symbol(part_name)) = tail_drain.next() {
                        // collect next symbols
                        Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
                            Command::ExportDotPart((filename, part_name)),
                        )))
                    } else {
                        None
                    }
                }
                "live" => {
                    let mut id_tags = BTreeSet::new();
                    // expect more tags
                    while let Some(EvaluatedExpr::Symbol(si)) = tail_drain.next() {
                        id_tags.insert(si);
                    }
                    // collect next symbols
                    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
                        Command::ExportDotRunning((filename, id_tags)),
                    )))
                }
                _ => None,
            }
        }
        _ => None,
    }
}

pub fn once(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let tail_drain = tail.drain(..).skip(1);
    let mut sound_events = Vec::new();
    let mut control_events = Vec::new();

    for c in tail_drain {
        match c {
            EvaluatedExpr::BuiltIn(BuiltIn::SoundEvent(mut e)) => {
                sound_events.push(e.get_static());
            }
            EvaluatedExpr::BuiltIn(BuiltIn::ControlEvent(c)) => control_events.push(c),
            _ => {}
        }
    }

    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(Command::Once((
        sound_events,
        control_events,
    )))))
}

pub fn step_part(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    if let Some(EvaluatedExpr::Symbol(s)) = tail_drain.next() {
        Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(Command::StepPart(
            s,
        ))))
    } else {
        None
    }
}

pub fn clear(
    _: &FunctionMap,
    _: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(Command::Clear)))
}

pub fn connect_visualizer(
    _: &FunctionMap,
    _: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::ConnectVisualizer,
    )))
}

pub fn start_recording(
    _: &FunctionMap,
    tail: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    let mut tail_drain = tail.drain(..).skip(1);
    let prefix = if let Some(EvaluatedExpr::String(s)) = tail_drain.next() {
        Some(s)
    } else {
        None
    };

    let mut rec_input = false;
    while let Some(c) = tail_drain.next() {
        if let EvaluatedExpr::Keyword(k) = c {
            if k.as_str() == "input" {
                // default is zero ...
                if let Some(EvaluatedExpr::Boolean(b)) = tail_drain.next() {
                    rec_input = b;
                }
            }
        }
    }

    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::StartRecording(prefix, rec_input),
    )))
}

pub fn stop_recording(
    _: &FunctionMap,
    _: &mut Vec<EvaluatedExpr>,
    _: &sync::Arc<GlobalParameters>,
    _: &sync::Arc<Mutex<SampleAndWavematrixSet>>,
    _: OutputMode,
) -> Option<EvaluatedExpr> {
    Some(EvaluatedExpr::BuiltIn(BuiltIn::Command(
        Command::StopRecording,
    )))
}