classdef lang2_sound

    properties (Constant)
        cons = ["b", "v", "ʐ", "z", "j", "k", "m", "r", "s", "t", "NONE"]
        vowels =    ["a",   "o",    "ɐ",    "ɨ",   "ə",  "ɪ̈", "NONE"]
        f1_erbs =   [14.0,  11.0,   13.0,   9.0,   12.0, 10.0, 0.0]
        f2_erbs =   [19.0,  16.5,   18.5,   21.5,  18.5, 20.0, 0.0]
        f1_std =    [0.7,   0.7,    0.6,    0.8,   0.9,  0.7]
        f2_std =    [0.5,   1,      1.1,    0.8,   1,    0.4]
        % f1_erbs =   [14.0,  11.0,   13.0,   8.5,   14.0, 8.5, 0.0];
        % f2_erbs =   [19.0,  16.5,   18.5,   21.5,  19.0, 21.5, 0.0]
        n_cons = size(lang2_sound.cons, 2) - 1
        n_vowels = size(lang2_sound.vowels, 2) - 1
        n_auditory_nodes = 2 * lang2_sound.n_cons + 2 * vowel.n_auditory_nodes

        all_sounds = lang2_sound.get_list_of_all_sounds % array 5 x 23(including NONE)
        n_sounds = size(lang2_sound.all_sounds, 2) - 1    
    end
    
    properties (SetAccess = immutable)
        c1_index uint32
        v1_index uint32
        c2_index uint32
        v2_index uint32
    end

    methods
        function obj = lang2_sound(c1_logical_vector, v1_logical_vector, ...
                c2_logical_vector, v2_logical_vector)
            % consonant 1
            obj.c1_index = find(c1_logical_vector, 1, 'first');
            % for NONE
            if isempty(obj.c1_index)
                obj.c1_index = obj.n_cons + 1;
            end

            % consonant 2
            obj.c2_index = find(c2_logical_vector, 1, 'first');
            % for NONE
            if isempty(obj.c2_index)
                obj.c2_index = obj.n_cons + 1;
            end

            % vowel 1
            % for one of the vowels
            obj.v1_index = find(v1_logical_vector, 1, 'first');
            % for NONE
            if isempty(obj.v1_index)
                obj.v1_index = obj.n_vowels + 1;
            end

            % vowel 2
            % for one of the vowels
            obj.v2_index = find(v2_logical_vector, 1, 'first');          
            % for NONE
            if isempty(obj.v2_index)
                obj.v2_index = obj.n_vowels + 1;
            end            
        end 
        
        function as_index = all_sounds_index(obj)
            c1 = lang2_sound.cons(obj.c1_index);
            v1 = lang2_sound.vowels(obj.v1_index);
            c2 = lang2_sound.cons(obj.c2_index);
            v2 = lang2_sound.vowels(obj.v2_index);
            as_index = find(strcmp(lang2_sound.all_sounds(2,:), c1) ...
                & strcmp(lang2_sound.all_sounds(3,:), v1) ...
                & strcmp(lang2_sound.all_sounds(4,:), c2) ...
                & strcmp(lang2_sound.all_sounds(5,:), v2), ...
                1, "first");
        end

        function input_vector = sample_and_create_input_vector(obj)
            c1_vector = lang2_sound.create_consonant_input_vector(obj.c1_index);
            c2_vector = lang2_sound.create_consonant_input_vector(obj.c2_index);

            % v1: sampling if f1 and f2 are not 0
            v1 = obj.v1_index;
            if obj.f1_erbs(v1) && obj.f2_erbs(v1)
                [v1_f1, v1_f2] = vowel.sample_with_std( ...
                    obj.f1_erbs(v1), obj.f2_erbs(v1), ...
                    obj.f1_std(v1), obj.f2_std(v1));
            else
                v1_f1 = 0;
                v1_f2 = 0;
            end
            v1_vector = vowel.create_input_vector(v1_f1, v1_f2);
            
            % v2: sampling if f1 and f2 are not 0
            v2 = obj.v2_index;
            if obj.f1_erbs(v2) && obj.f2_erbs(v2)
                [v2_f1, v2_f2] = vowel.sample_with_std( ...
                    obj.f1_erbs(v2), obj.f2_erbs(v2), ...
                    obj.f1_std(v2), obj.f2_std(v2));
            else
                v2_f1 = 0;
                v2_f2 = 0;
            end
            v2_vector = vowel.create_input_vector(v2_f1, v2_f2);

            input_vector = [c1_vector v1_vector c2_vector v2_vector];
        end

        function input_vector = create_input_vector(obj)
            c1_vector = lang2_sound.create_consonant_input_vector(obj.c1_index);
            c2_vector = lang2_sound.create_consonant_input_vector(obj.c2_index);
            v1_vector = vowel.create_input_vector(obj.f1_erbs(obj.v1_index), obj.f2_erbs(obj.v1_index));
            v2_vector = vowel.create_input_vector(obj.f1_erbs(obj.v2_index), obj.f2_erbs(obj.v2_index));

            input_vector = [c1_vector v1_vector c2_vector v2_vector];
        end
    end

    methods (Static)
        function sound = get_sound_by_index(s_index)
            s_cell_array = enumeration('lang2_sound');
            sound = s_cell_array(s_index);
        end

        function v_index = find_vowel_by_erbs(f1_erb, f2_erb)
            % if found, returns v_index 
            % else, returns lang2_sound.n_vowels + 2
            found = false;
            for i = 1:lang2_sound.n_vowels + 1
                if (f1_erb == lang2_sound.f1_erbs(i) && f2_erb == lang2_sound.f2_erbs(i))
                    found = true;
                    v_index = i;
                    break
                end
            end
            if ~found
                v_index = lang2_sound.n_vowels + 2;
            end
        end
               
        function all_sounds = get_list_of_all_sounds()
            s_cell_array = enumeration('lang2_sound');
            
            n_sounds = size(s_cell_array, 1);
            all_sounds = strings(5, n_sounds);
            
            for i = 1:n_sounds
                sound = s_cell_array(i);
                c1 = lang2_sound.cons(sound.c1_index);
                v1 = lang2_sound.vowels(sound.v1_index);
                c2 = lang2_sound.cons(sound.c2_index);
                v2 = lang2_sound.vowels(sound.v2_index);
                
                all_sounds(2, i) = c1;
                all_sounds(3, i) = v1;
                all_sounds(4, i) = c2;
                all_sounds(5, i) = v2;

                sound_length = 4;
                if strcmp(c1, lang2_sound.cons(lang2_sound.n_cons + 1))
                    c1 = "";
                    sound_length = sound_length - 1;
                end
                if strcmp(c2, lang2_sound.cons(lang2_sound.n_cons + 1))
                    c2 = "";
                    sound_length = sound_length - 1;
                end
                if strcmp(v1, lang2_sound.vowels(lang2_sound.n_vowels + 1))
                    v1 = "";
                    sound_length = sound_length - 1;
                end
                if strcmp(v2, lang2_sound.vowels(lang2_sound.n_vowels + 1))
                    v2 = "";
                    sound_length = sound_length - 1;
                end

                if sound_length
                    all_sounds(1, i) = strcat(c1, v1, c2, v2);
                else
                    all_sounds(1, i) = "NONE";
                end
            end
        end

        function c_vector = create_zero_consonant_input_vector()
            c_vector = zeros(1, lang2_sound.n_cons);
        end

        function c_vector = create_consonant_input_vector(cons_index)
            c_vector = zeros(1, lang2_sound.n_cons);
            if cons_index <= lang2_sound.n_cons
                c_vector(cons_index) = 1;
                c_vector = 6.5 * c_vector - 1;
            else
                c_vector = c_vector - 1;
            end
        end

        function [c1_vector, v1_vector, c2_vector, v2_vector] = split_sound_vector(sound_vector)
            nc = lang2_sound.n_cons;
            nv = vowel.n_auditory_nodes;
            
            c1_vector = sound_vector(1:nc);
            v1_vector = sound_vector(nc+1:nc+nv);
            c2_vector = sound_vector(nc+nv+1:2*nc+nv);
            v2_vector = sound_vector(2*nc+nv+1:2*nc+2*nv);
        end

        function draw_zero_input()
            draw.consonant(zeros(1, lang2_sound.n_cons), draw.lang2_consonant1_input)
            draw.consonant(zeros(1, lang2_sound.n_cons), draw.lang2_consonant2_input)
            draw.vowel(zeros(1, vowel.n_auditory_nodes), draw.lang2_vowel1_input)
            draw.vowel(zeros(1, vowel.n_auditory_nodes), draw.lang2_vowel2_input)
        end

        function draw_zero_output()
            draw.consonant(zeros(1, lang2_sound.n_cons), draw.lang2_consonant1_output)
            draw.consonant(zeros(1, lang2_sound.n_cons), draw.lang2_consonant2_output)
            draw.vowel(zeros(1, vowel.n_auditory_nodes), draw.lang2_vowel1_output)
            draw.vowel(zeros(1, vowel.n_auditory_nodes), draw.lang2_vowel2_output)
        end
       
        function draw_input(sound_input_vector)
            assert(lang2_sound.n_auditory_nodes == size(sound_input_vector, 2), ...
                "incorrect sound_input_vector size")
            [c1_vector, v1_vector, c2_vector, v2_vector] = lang2_sound.split_sound_vector(sound_input_vector);

            draw.consonant(c1_vector, draw.lang2_consonant1_input)
            draw.consonant(c2_vector, draw.lang2_consonant2_input)
            draw.vowel(v1_vector, draw.lang2_vowel1_input)
            draw.vowel(v2_vector, draw.lang2_vowel2_input)
        end

        function draw_output(sound_output_vector)
            assert(lang2_sound.n_auditory_nodes == size(sound_output_vector, 2), ...
                "incorrect sound_output_vector size")
            [c1_vector, v1_vector, c2_vector, v2_vector] = lang2_sound.split_sound_vector(sound_output_vector);
            
            draw.consonant(c1_vector, draw.lang2_consonant1_output)
            draw.consonant(c2_vector, draw.lang2_consonant2_output)
            draw.vowel(v1_vector, draw.lang2_vowel1_output)
            draw.vowel(v2_vector, draw.lang2_vowel2_output)
        end
    end 

    enumeration
        SOVA  ([0 0 0 0 0 0 0 0 1 0], [0 0 1 0 0 0], [0 1 0 0 0 0 0 0 0 0], [1 0 0 0 0 0])
        SOVY  ([0 0 0 0 0 0 0 0 1 0], [0 1 0 0 0 0], [0 1 0 0 0 0 0 0 0 0], [0 0 0 0 0 1])
        ROZA  ([0 0 0 0 0 0 0 1 0 0], [0 1 0 0 0 0], [0 0 0 1 0 0 0 0 0 0], [0 0 0 0 1 0])
        ROZY  ([0 0 0 0 0 0 0 1 0 0], [0 1 0 0 0 0], [0 0 0 1 0 0 0 0 0 0], [0 0 0 0 0 1])
        KOT   ([0 0 0 0 0 1 0 0 0 0], [0 1 0 0 0 0], [0 0 0 0 0 0 0 0 0 1], [0 0 0 0 0 0])
        KOTY  ([0 0 0 0 0 1 0 0 0 0], [0 0 1 0 0 0], [0 0 0 0 0 0 0 0 0 1], [0 0 0 1 0 0])
        BOT   ([1 0 0 0 0 0 0 0 0 0], [0 1 0 0 0 0], [0 0 0 0 0 0 0 0 0 1], [0 0 0 0 0 0])
        BOTY  ([1 0 0 0 0 0 0 0 0 0], [0 1 0 0 0 0], [0 0 0 0 0 0 0 0 0 1], [0 0 0 0 0 1])
        MOJA  ([0 0 0 0 0 0 1 0 0 0], [0 0 1 0 0 0], [0 0 0 0 1 0 0 0 0 0], [1 0 0 0 0 0])
        MOJ   ([0 0 0 0 0 0 1 0 0 0], [0 1 0 0 0 0], [0 0 0 0 1 0 0 0 0 0], [0 0 0 0 0 0])
        MOJY  ([0 0 0 0 0 0 1 0 0 0], [0 0 1 0 0 0], [0 0 0 0 1 0 0 0 0 0], [0 0 0 1 0 0])
        ZHARA ([0 0 1 0 0 0 0 0 0 0], [0 0 1 0 0 0], [0 0 0 0 0 0 0 1 0 0], [1 0 0 0 0 0])
        ZHAR  ([0 0 1 0 0 0 0 0 0 0], [1 0 0 0 0 0], [0 0 0 0 0 0 0 1 0 0], [0 0 0 0 0 0])
        ZHABA ([0 0 1 0 0 0 0 0 0 0], [1 0 0 0 0 0], [1 0 0 0 0 0 0 0 0 0], [0 0 0 0 1 0])
        ZHABY ([0 0 1 0 0 0 0 0 0 0], [1 0 0 0 0 0], [1 0 0 0 0 0 0 0 0 0], [0 0 0 0 0 1])
        TAZ   ([0 0 0 0 0 0 0 0 0 1], [1 0 0 0 0 0], [0 0 0 1 0 0 0 0 0 0], [0 0 0 0 0 0])
        TAZY  ([0 0 0 0 0 0 0 0 0 1], [0 0 1 0 0 0], [0 0 0 1 0 0 0 0 0 0], [0 0 0 1 0 0])
        BAR   ([1 0 0 0 0 0 0 0 0 0], [1 0 0 0 0 0], [0 0 0 0 0 0 0 1 0 0], [0 0 0 0 0 0])
        BARY  ([1 0 0 0 0 0 0 0 0 0], [1 0 0 0 0 0], [0 0 0 0 0 0 0 1 0 0], [0 0 0 0 0 1])
        RABA  ([0 0 0 0 0 0 0 1 0 0], [0 0 1 0 0 0], [1 0 0 0 0 0 0 0 0 0], [1 0 0 0 0 0])
        RAB   ([0 0 0 0 0 0 0 1 0 0], [1 0 0 0 0 0], [1 0 0 0 0 0 0 0 0 0], [0 0 0 0 0 0])
        RABY  ([0 0 0 0 0 0 0 1 0 0], [0 0 1 0 0 0], [1 0 0 0 0 0 0 0 0 0], [0 0 0 1 0 0])
        NONE  ([0 0 0 0 0 0 0 0 0 0], [0 0 0 0 0 0], [0 0 0 0 0 0 0 0 0 0], [0 0 0 0 0 0])
    end

end

