library ieee;
use ieee.std_logic_1164.all;
--use ieee.std_logic_arith.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;

library work;
use work.functions.all;
use work.soundtrack.all;

entity de2_wm8731_audio is
port (
	clk				: in std_logic;       --  Audio CODEC Chip Clock AUD_XCK (18.432 MHz)
	reset_n			: in std_logic;
	test_mode		: in std_logic;       --    Audio CODEC controller test mode
	audio_request	: out std_logic;  --    Audio controller request new data
	data			: in unsigned(15 downto 0);
	frq_divider1	: in unsigned(15 downto 0);
	frq_divider2	: in unsigned(15 downto 0);
	audio_volume1	: in unsigned(1 downto 0);
	audio_volume2	: in unsigned(1 downto 0);
	audio_track1	: in unsigned(1 downto 0);
	audio_track2	: in unsigned(1 downto 0);
	audio_vol		: in unsigned(1 downto 0);
--	press_delay		: in integer;
--	tone			: in unsigned(1 downto 0);

--	mul_channel		: in std_logic;
--	num_channel		: in std_logic;
--	cycle_divider	: in unsigned(9 downto 0);
  
    -- Audio interface signals
    AUD_ADCLRCK  : out  std_logic;   --    Audio CODEC ADC LR Clock
    AUD_ADCDAT   : in   std_logic;   --    Audio CODEC ADC Data
    AUD_DACLRCK  : out  std_logic;   --    Audio CODEC DAC LR Clock
    AUD_DACDAT   : out  std_logic;   --    Audio CODEC DAC Data
    AUD_BCLK     : inout std_logic  --    Audio CODEC Bit-Stream Clock
  );
end  de2_wm8731_audio;

architecture rtl of de2_wm8731_audio is   

component de2_audio_pll is
port (
inclk0		: in std_logic;
c0			: out std_logic 
);
end component;  

signal lrck 		: std_logic;
signal bclk 		: std_logic;
signal xck  		: std_logic;
signal scale		: std_logic;
signal audio_clock	: std_logic;

signal lrck_divider  : unsigned(7 downto 0); 
signal bclk_divider  : unsigned(3 downto 0);
signal scale_divider1: unsigned(15 downto 0);
signal scale_divider2: unsigned(15 downto 0);

signal set_bclk : std_logic;
signal set_lrck : std_logic;
signal set_scale: std_logic;
signal clr_bclk : std_logic;
signal scale_lat: std_logic;

signal sin_out1    : std_logic_vector(15 downto 0);
signal sin_out2    : std_logic_vector(15 downto 0);
signal sin_counter1: unsigned(11 downto 0);
signal sin_counter2: unsigned(11 downto 0);
signal sin_out3: std_logic_vector(15 downto 0);
signal sin_out4: std_logic_vector(15 downto 0);
signal freq_lat    : unsigned(15 downto 0);
signal shift_out   : unsigned(15 downto 0);

--constant PRESS_DELAY_MAX : integer := 8000000;

begin
  
    -- LRCK divider 
    -- Audio chip main clock is 18.432MHz / Sample rate 48KHz
    -- Divider is 18.432 MHz / 48KHz = 192 (X"C0")
    -- Left justify mode set by I2C controller

  audio_pll: de2_audio_pll port map (
	inclk0	=> clk,
	c0		=> audio_clock
  );

  process (audio_clock)
  begin
    if rising_edge(audio_clock) then
      if reset_n = '0' then 
        lrck_divider <= (others => '0');
      elsif lrck_divider = X"BF"  then        -- "C0" minus 1
        lrck_divider <= X"00";
      else 
        lrck_divider <= lrck_divider + 1;
      end if;
    end if;   
  end process;

  process (audio_clock)
  begin
    if rising_edge(audio_clock) then      
      if reset_n = '0' then 
        bclk_divider <= (others => '0');
      elsif bclk_divider = X"B" or set_lrck = '1' then  --
        bclk_divider <= X"0";
      else 
        bclk_divider <= bclk_divider + 1;
      end if;
    end if;
  end process;

  set_lrck <= '1' when lrck_divider = X"BF" else '0';

  process (audio_clock)
  begin
    if rising_edge(audio_clock) then
      if reset_n = '0' then
        lrck <= '0';
      elsif set_lrck = '1' then -- 
        lrck <= not lrck;
      end if;
    end if;
  end process;
    
  -- BCLK divider
  set_bclk <= '1' when bclk_divider(3 downto 0) = "0101" else '0';
  clr_bclk <= '1' when bclk_divider(3 downto 0) = "1011" else '0';
  
  process (audio_clock)
  begin
    if rising_edge(audio_clock) then
      if reset_n = '0' then
        bclk <= '0';
      elsif set_lrck = '1' or clr_bclk = '1' then
        bclk <= '0';
      elsif set_bclk = '1' then 
        bclk <= '1';
      end if;
    end if;
  end process;

  -- Audio data shift output
  process (audio_clock)
  begin
    if rising_edge(audio_clock) then
      if reset_n = '0' then
        shift_out <= (others => '0');
      elsif set_lrck = '1' then            -------
        if test_mode = '1' then
		  -- soundtrack selection
		  if audio_track1 = "00" then
			sin_out1 <= s_shr(std_logic_vector(default(to_integer(sin_counter1))), to_integer(audio_volume1));
		  end if;
			sin_out3 <= s_shr(std_logic_vector(jump(to_integer(sin_counter2))), to_integer(audio_volume2));
			sin_out4 <= s_shr(std_logic_vector(collision(to_integer(sin_counter2))), to_integer(audio_volume2));

		  if audio_track2 = "00" then
			sin_out2 <= sin_out3;
		  elsif audio_track2 = "01" then
			sin_out2 <= sin_out4;
		  end if;
		  shift_out <= unsigned(s_shr(sin_out1 + sin_out2, to_integer(audio_vol)));
        else 
          shift_out <= data;
        end if;
      elsif clr_bclk = '1' then 
        shift_out <= shift_out (14 downto 0) & '0';
      end if;
    end if;   
  end process;

    -- Audio outputs
    
    AUD_ADCLRCK  <= lrck;          
    AUD_DACLRCK  <= lrck;          
    AUD_DACDAT   <= shift_out(15); 
    AUD_BCLK     <= bclk;          

    -- Self test with Sin wave
    process (audio_clock)
	begin
		if rising_edge(audio_clock) then
			if reset_n = '0' then 
				scale_divider1 <= (others => '0');
			elsif scale_divider1 = frq_divider1 then        -- "C0" minus 1
				scale_divider1 <= X"0000";
			else 
				scale_divider1 <= scale_divider1 + 1;
			end if;
		end if;   
    end process;

    process (audio_clock)
	begin
	  if rising_edge(audio_clock) then
        if reset_n = '0' then 
          scale_divider2 <= (others => '0');
        elsif scale_divider2 = frq_divider2 then        -- "C0" minus 1
          scale_divider2 <= X"0000";
        else 
          scale_divider2 <= scale_divider2 + 1;
        end if;
      end if;   
    end process;

    process(audio_clock)      
    begin
      if rising_edge(audio_clock) then
        if reset_n = '0' then 
            sin_counter1 <= (others => '0');
        elsif scale_divider1 = frq_divider1 - 1  then  
          if sin_counter1 = "000010001111" then 
            sin_counter1 <= "000000000000";
          else  
            sin_counter1 <= sin_counter1 + 1;
          end if;
        end if;
      end if;
    end process;

	process(audio_clock)
	begin
	  if rising_edge(audio_clock) then
	  freq_lat	<= frq_divider2;
	  end if;
	end process;

    process(audio_clock)      
    begin
      if rising_edge(audio_clock) then
        if reset_n = '0' then 
            sin_counter2 <= (others => '0');
		elsif freq_lat /= frq_divider2 then
			sin_counter2 <= "000000000000";
--		elsif audio_track2 = "00" and press_delay > PRESS_DELAY_MAX - 1 then
--			sin_counter2 <= "000000000000";
        elsif scale_divider2 = frq_divider2 - 2  then  
          if sin_counter2 = "011000111111" then 
            sin_counter2 <= "000000000000";
          else  
            sin_counter2 <= sin_counter2 + 1;
          end if;
        end if;
      end if;
    end process;

end architecture;


