library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; entity samples is port( -- Sound related audio_enabled : in std_logic; audio_port_0 : in std_logic_vector( 7 downto 0); audio_port_1 : in std_logic_vector( 7 downto 0); audio_in : in std_logic_vector(15 downto 0); audio_out_L : out std_logic_vector(15 downto 0); audio_out_R : out std_logic_vector(15 downto 0); -- Access to samples wave_addr : inout std_logic_vector(27 downto 0); wave_read : out std_logic; wave_data : in std_logic_vector(31 downto 0); -- table loading dl_addr : in std_logic_vector(24 downto 0); dl_wr : in std_logic; dl_data : in std_logic_vector( 7 downto 0); dl_download : in std_logic; samples_ok : out std_logic; -- Clocks and things CLK_SYS : in std_logic; -- 10Mhz (for loading table) clock : in std_logic; -- 80Mhz (this drives the rest) reset : in std_logic -- high to reset ); end samples; architecture struct of samples is -- Clock dividers signal wav_clk_cnt : std_logic_vector(11 downto 0); -- 44kHz divider / sound counter (80Mhz count to 1814 (x"716") for 44khz clock) signal wav_freq_cnt : std_logic_vector(1 downto 0); -- divide further to give 22Khz (0) and 11Khz (1) signal wav_freq_lst : std_logic_vector(1 downto 0); -- for rising edge checks -- wave info (aka Table) type addr_t is array (0 to 15) of std_logic_vector(23 downto 0); type mode_t is array (0 to 15) of std_logic_vector(15 downto 0); signal wav_addr_start : addr_t; signal wav_addr_end : addr_t; signal wav_mode : mode_t := (others=>(others=>'0')); signal table_loaded : std_logic register := '0'; signal wave_left : std_logic_vector(15 downto 0) register := (others=>'0'); signal wave_right : std_logic_vector(15 downto 0) register := (others=>'0'); signal wave_read_ct : std_logic_vector(2 downto 0) register := (others=>'0'); -- sound control info signal snd_id : integer; signal snd_addr_play : addr_t := (others=>(others=>'1')); signal ports : std_logic_vector(15 downto 0); signal last_ports : std_logic_vector(15 downto 0); signal this_ports : std_logic_vector(15 downto 0); signal next_ports : std_logic_vector(15 downto 0); -- Audio variables signal audio_sum_l : signed(19 downto 0); signal audio_sum_r : signed(19 downto 0); signal audio_l : signed(19 downto 0); signal audio_r : signed(19 downto 0); begin ---------------- -- Table Load -- ---------------- -- wav_mode - 8 bits - if byte = 00 then this bit does not trigger anything -- bit 0 = 11khz -- bit 1 = 22khz -- bit 2 = 44khz -- bit 4 = 16 bit (off = 8 bit) -- bit 5 = Stereo (off = mono) -- -- trigger mode - 8 bits -- bit 0 = ON one shot (sample plays once) -- bit 0 = OFF restarts if bit still active at end (loops) -- bit 1 = ON cuts off sample if bit goes low (should it fade?) -- bit 1 = OFF continues until end of sample reached -- bit 4 = output LEFT channel -- bit 5 = output RIGHT channel (set both for MONO/STEREO) process (CLK_SYS,dl_download,dl_wr,dl_data) variable ID : integer; begin if rising_edge(CLK_SYS) then if dl_download='1' and dl_wr='1' then ID := to_integer(unsigned(dl_addr(6 downto 3))); case dl_addr(2 downto 0) is when "000" => -- Wave mode wav_mode(ID)(7 downto 0) <= dl_data; if dl_data(2 downto 0) /= "000" then table_loaded <= '1'; end if; when "001" => -- Trigger mode wav_mode(ID)(15 downto 8) <= dl_data; when "010" => -- Start Address wav_addr_start(ID)(23 downto 16) <= dl_data; when "011" => -- Start Address wav_addr_start(ID)(15 downto 8) <= dl_data; when "100" => -- Start Address wav_addr_start(ID)(7 downto 0) <= dl_data; when "101" => -- End Address wav_addr_end(ID)(23 downto 16) <= dl_data; when "110" => -- End Address wav_addr_end(ID)(15 downto 8) <= dl_data; when "111" => -- End Address wav_addr_end(ID)(7 downto 0) <= dl_data; end case; end if; end if; end process; ----------------- -- Wave player -- ----------------- -- current IO bit & sample to be looking at snd_id <= to_integer(unsigned(wav_clk_cnt(9 downto 6))); ports <= audio_port_1 & audio_port_0; samples_ok <= table_loaded; -- wave player process (clock, reset, table_loaded) begin if table_loaded='1' then if reset='1' then wav_clk_cnt <= (others=>'0'); wav_freq_cnt <= "00"; snd_addr_play <= (others=>(others=>'1')); wave_read <= '0'; audio_out_L <= x"0000"; audio_out_R <= x"0000"; else -- Use falling edge to interleave commands with SDRAM module if falling_edge(clock) then -- make sure we don't miss any bits being set next_ports <= next_ports or ports; -- make sure we don't miss any bits being cleared last_ports <= last_ports and ports; if snd_addr_play(snd_id)=x"FFFFFF" then -- All Start play on 0 to 1 transition if (last_ports(snd_id)='0' and this_ports(snd_id)='1') then snd_addr_play(snd_id) <= wav_addr_start(snd_id); end if; else -- cut out when signal zero if (wav_mode(snd_id)(9)='1' and this_ports(snd_id)='0') then snd_addr_play(snd_id) <= x"FFFFFF"; end if; end if; -- 44.1kHz base tempo / high bits for scanning sound if wav_clk_cnt = x"716" then -- divide 80MHz by 1814 => 44.101kHz wav_clk_cnt <= (others=>'0'); wav_freq_lst <= wav_freq_cnt; wav_freq_cnt <= wav_freq_cnt + '1'; -- cycle along ports last / this last_ports <= this_ports; this_ports <= next_ports; next_ports <= ports; -- latch final audio / reset sum audio_r <= audio_sum_r; audio_l <= audio_sum_l; audio_sum_r <= resize(signed(audio_in), 20); audio_sum_l <= resize(signed(audio_in), 20); else wav_clk_cnt <= wav_clk_cnt + 1; end if; if audio_enabled='1' then -- -- clip audio -- if audio_r(19 downto 2) > 32767 then -- audio_out_R <= x"7FFF"; -- elsif audio_r(19 downto 2) < -32768 then -- audio_out_R <= x"8000"; -- else -- audio_out_R <= std_logic_vector(audio_r(17 downto 2)); -- end if; -- -- if audio_l(19 downto 2) > 32767 then -- audio_out_L <= x"7FFF"; -- elsif audio_l(19 downto 2) < -32768 then -- audio_out_L <= x"8000"; -- else -- audio_out_L <= std_logic_vector(audio_l(17 downto 2)); -- end if; audio_out_R <= std_logic_vector(audio_r(17 downto 2)); audio_out_L <= std_logic_vector(audio_l(17 downto 2)); else audio_out_L <= x"0000"; audio_out_R <= x"0000"; end if; -- sdram read trigger (and auto refresh period) if wav_clk_cnt(5 downto 0) = "000000" then wave_read <= '1';end if; if wav_clk_cnt(5 downto 0) = "000100" then wave_read <= '0';end if; -- select only useful cycles (0-15) if wav_clk_cnt(10)='0' then -- is this sample present if wav_mode(snd_id)(2 downto 0) /= "000" then if snd_addr_play(snd_id) /= x"FFFFFF" then --------------- -- Data read -- --------------- -- set addr for first byte (but it reads 4 bytes anyway) if wav_clk_cnt(5 downto 0) = "000000" then wave_addr <= "0000" & snd_addr_play(snd_id); end if; if wav_clk_cnt(5 downto 0) = "111101" then -- SDRAM bit : data returned, put into left / right accordingly case wav_mode(snd_id)(5 downto 4) is when "00" => -- 8 bit mono if wave_addr(0)='0' then -- Low byte wave_left <= (not wave_data(23)) & wave_data(22 downto 16) & x"00"; wave_right <= (not wave_data(23)) & wave_data(22 downto 16) & x"00"; else -- high byte wave_left <= (not wave_data(31)) & wave_data(30 downto 24) & x"00"; wave_right <= (not wave_data(31)) & wave_data(30 downto 24) & x"00"; end if; when "01" => -- 16 bit mono wave_left <= wave_data(31 downto 16); wave_right <= wave_data(31 downto 16); when "10" => -- 8 bit stereo wave_left <= (not wave_data(23)) & wave_data(22 downto 16) & x"00"; wave_right <= (not wave_data(31)) & wave_data(30 downto 24) & x"00"; when "11" => -- 16 bit stereo (will only play 16 bit mono as SDRAM not reading 32 bit currently) wave_left <= wave_data(31 downto 16); wave_right <= wave_data(15 downto 0); end case; end if; -- Data all read, add to output counters if wav_clk_cnt(5 downto 0) = "111110" then -- Left channel if wav_mode(snd_id)(12)='1' then audio_sum_l <= audio_sum_l + to_integer(signed(wave_left)); end if; -- Right channel if wav_mode(snd_id)(13)='1' then audio_sum_r <= audio_sum_r + to_integer(signed(wave_right)); end if; --wave_left <= x"0000"; --wave_right <= x"0000"; -- Increment address depending on frequency and size if wav_mode(snd_id)(2)='1' or (wav_mode(snd_id)(1)='1' and wav_freq_lst(0)='0' and wav_freq_cnt(0)='1') or (wav_mode(snd_id)(0)='1' and wav_freq_lst(1)='0' and wav_freq_cnt(1)='1') then case wav_mode(snd_id)(5 downto 4) is when "00" => -- 8 bit mono snd_addr_play(snd_id) <= snd_addr_play(snd_id) + 1; when "01" | "10" => -- 16 bit mono or 8 bit stereo snd_addr_play(snd_id) <= snd_addr_play(snd_id) + 2; when "11" => -- 16 bit stereo snd_addr_play(snd_id) <= snd_addr_play(snd_id) + 4; end case; end if; end if; if wav_clk_cnt(5 downto 0) = "111111" then -- End of Wave data ? if snd_addr_play(snd_id) > wav_addr_end(snd_id) then -- Restart ? if (wav_mode(snd_id)(8)='0' and this_ports(snd_id)='1') then -- Loop back to the start snd_addr_play(snd_id) <= wav_addr_start(snd_id); else -- Stop snd_addr_play(snd_id) <= x"FFFFFF"; end if; end if; end if; end if; -- Playing end if; -- Bit Active end if; -- useful end if; -- rising clock end if; -- reset end if; -- table loaded end process; end;