#!/usr/bin/perl -w -I ../../lib

use 5.018;

use strict;

use Carp;

{ package Audio::Signal::Synth;
    use Moose;
    use Moose::Util::TypeConstraints;
    use Data::Dumper;
    
    has 'tones' => (
        is => 'rw',
        isa => 'ArrayRef',
        default => sub { return([]); },
    );
  
    has 'effects' => (
        is => 'rw',
        isa => 'ArrayRef',
        default => sub { return([]); },
    );
    
    has 'length' => (
        is => 'rw',
        isa => 'Num',
    );
    
    around BUILDARGS => sub {
        my $self = shift;
        my $class = shift;
        my $orig = shift;
        
        my $prepared;
        
        $prepared->{length} = $orig->{length};
      
        for my $cfg_tones (@{$orig->{tones}}) {
            while(my ($cfg_tone_type,$cfg_tone_attrs) = each(%{$cfg_tones})) {
                my $prepared_tone;
                given($cfg_tone_type) {
                    when(/^brownnoise$/) {
                        $prepared_tone = Audio::Signal::Tone::BrownNoise->new(%{$cfg_tone_attrs})
                    }
                    
                    when(/^exp$/) {
                        $prepared_tone = Audio::Signal::Tone::Exp->new(%{$cfg_tone_attrs})
                    }
                    
                    when(/^noise$/) {
                        $prepared_tone = Audio::Signal::Tone::Noise->new(%{$cfg_tone_attrs})
                    }
                    
                    when(/^pinknoise$/) {
                        $prepared_tone = Audio::Signal::Tone::PinkNoise->new(%{$cfg_tone_attrs})
                    }
                    
                    when(/^pluck$/) {
                        $prepared_tone = Audio::Signal::Tone::Pluck->new(%{$cfg_tone_attrs})
                    }
                    
                    when(/^sawtooth$/) {
                        $prepared_tone = Audio::Signal::Tone::Sawtooth->new(%{$cfg_tone_attrs})
                    }
                    
                    when(/^sine$/) {
                        $prepared_tone = Audio::Signal::Tone::Sine->new(%{$cfg_tone_attrs})
                    }
                    
                    when(/^square$/) {
                        $prepared_tone = Audio::Signal::Tone::Square->new(%{$cfg_tone_attrs})
                    }
                    
                    when(/^tpdfnoise$/) {
                        $prepared_tone = Audio::Signal::Tone::TPDFNoise->new(%{$cfg_tone_attrs})
                    }
                    
                    when(/^trapezium$/) {
                        $prepared_tone = Audio::Signal::Tone::Trapezium->new(%{$cfg_tone_attrs})
                    }
                                        
                    when(/^triangle$/) {
                        $prepared_tone = Audio::Signal::Tone::Triangle->new(%{$cfg_tone_attrs})
                    }                    
                         
                    when(/^whitenoise$/) {
                        $prepared_tone = Audio::Signal::Tone::WhiteNoise->new(%{$cfg_tone_attrs})
                    }
                }
                
                push(@{$prepared->{tones}}, $prepared_tone);
            }
        }
        
        # effects collection, first pass
        for my $cfg_effects (@{$orig->{effects}}) {
            while(my ($cfg_effect_type,$cfg_effect_attrs) = each(%{$cfg_effects})) {
                my $prepared_effect;
                given($cfg_effect_type) {
                    when(/^fade$/) {
                        $prepared_effect = Audio::Signal::Effect::Fade->new(%{$cfg_effect_attrs});
                    }        
                }
                
                push(@{$prepared->{effects}}, $prepared_effect) if $prepared_effect;
            }
        }
        
        # effects collection, second pass
        for my $cfg_effects (@{$orig->{effects}}) {
            while(my ($cfg_effect_type,$cfg_effect_attrs) = each(%{$cfg_effects})) {
                my $prepared_effect;
                
                given($cfg_effect_type) {
                    when(/^overdrive$/) {
                        $prepared_effect = Audio::Signal::Effect::Overdrive->new(%{$cfg_effect_attrs});
                    }
                    
                    when(/^phaser$/) {
                        $prepared_effect = Audio::Signal::Effect::Phaser->new(%{$cfg_effect_attrs});
                    }
                    
                    when(/^chorus$/) {                        
                        $prepared_effect = Audio::Signal::Effect::Chorus->new(%{$cfg_effect_attrs});
                    }
                    
                    when(/^flanger$/) {
                        $prepared_effect = Audio::Signal::Effect::Flanger->new(%{$cfg_effect_attrs});
                    }
                    
                    when(/^delay$/) {
                        $prepared_effect = Audio::Signal::Effect::Delay->new(%{$cfg_effect_attrs});
                    }
                    
                    when(/^echo$/) {
                        $prepared_effect = Audio::Signal::Effect::Echo->new(%{$cfg_effect_attrs});
                    }
                    
                    when(/^echos$/) {
                        $prepared_effect = Audio::Signal::Effect::Echos->new(%{$cfg_effect_attrs});
                    }
                }
                
                push(@{$prepared->{effects}}, $prepared_effect) if $prepared_effect;
            }
        }
        
        return($prepared);
    };
    
    sub gencmd {
        my $self = shift;
        my $class = shift;
        
        my (@tone_cmds,@effect_cmds);
        
        for my $tone (@{$self->{tones}}) {            
            push(@tone_cmds,$tone->gencmd());
        }
        
        for my $effect (@{$self->{effects}}) {            
            push(@effect_cmds,$effect->gencmd());
        }
        
        my ($ret_tones,$ret_effects) = (join(' ',@tone_cmds),join(' ',@effect_cmds));
        
        return(join(' ',("synth",$self->{length},$ret_tones,$ret_effects)));
    }
}

1;
