WavePlay

From Hamsterworks Wiki!

Jump to: navigation, search

To play around with the embedded block RAM in the FPGA, and to also play around with 1-bit DACs I wrote a sample player. It was a quick hack, and leveraged the IP generator for counters and so on.

Output was just through one ear of a headphone connected between the DAC output and ground - not ideal, but as my development board has 220 Ohm resisters on all lines it couldn't harm it.

It could be used to provide audio feedback for a project.

The main source

Here it is:

----------------------------------------------------------------------------------
-- Module Name: Waveplay - Behavioral 
-- Version:     1.0
-- Author:      Mike Field (hamster@snap.net.nz)
--
-- When a button is puhed an 8 bitsample stored in a BRAM block is played through
-- through a 1bit DAC.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity WavePlay is
    Port ( Clk     : in  STD_LOGIC; 
           Btn    : in STD_LOGIC_VECTOR(0 downto 0); 
           JA         : out STD_LOGIC_VECTOR(1 downto 0)
           );
end WavePlay;

architecture Behavioral of WavePlay is
   attribute syn_black_box : boolean;

   -- A block ram component pre-initialised with sample data.
   Component WaveStore
       port (
           clka: IN std_logic;
           wea: IN std_logic_VECTOR(0 downto 0);
           addra: IN std_logic_VECTOR(13 downto 0);
           dina: IN std_logic_VECTOR(7 downto 0);
           douta: OUT std_logic_VECTOR(7 downto 0));
   end component;
   attribute syn_black_box of WaveStore: component is true;

   -- IP Counter that counts to Clk/WaveFrequency, then sets thresh0 
   component timebase
       port (
           clk: IN std_logic;
           ce: IN std_logic;
           thresh0: OUT std_logic;
           q: OUT std_logic_VECTOR(12 downto 0));
   end component;
   attribute syn_black_box of timebase: component is true;
    
   COMPONENT dac8
   PORT(
       Clk : IN std_logic;
       Reset : IN std_logic;
       Data : IN std_logic_vector(7 downto 0);          
       PulseStream : OUT std_logic
       );
   END COMPONENT;

   -- Counter to keep track of the address in BRAM
   component AddrCtr
       port (
       clk: IN std_logic;
       ce: IN std_logic;
       thresh0: OUT std_logic;
       q: OUT std_logic_VECTOR(13 downto 0));
   end component;
   attribute syn_black_box of addrCtr: component is true;

   signal address     : std_logic_vector(13 downto 0);
   signal data         : std_logic_vector(7 downto 0);
   signal advCounter : std_logic;
   signal pulses         : std_logic;
   signal tbce         : std_logic;
   signal playEnd        : std_logic;
begin

   tbce <= btn(0) or not  playEnd;
   JA(1) <= pulses;
   JA(0) <= pulses;
        
dac8_01: dac8 
       PORT MAP(
           Clk => Clk,
           Reset => '0',
           Data => data,
           PulseStream => pulses);

wavedata : WaveStore
       port map (
           clka => clk,
           wea => "0",
           addra => address,
           dina => "00000000",
           douta => data);
               
timebase_01 : timebase
       port map (
           clk => clk,
           ce => tbce,
           thresh0 => advCounter,
           q => open);

addrCtr_01 : addrCtr
       port map (
           clk => clk,
           ce => advCounter,
           thresh0 => playEnd,
           q => address);
end Behavioral;

1 Bit DAC

Here is the one bit DAC, for 8 bit samples. It came mostly from the 1bit DAC project at http://www.fpga4fun.com/PWM_DAC.html.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity dac8 is
   Port ( Clk : in  STD_LOGIC;
	  Reset : in STD_LOGIC;
         Data : in  STD_LOGIC_VECTOR (7 downto 0);
         PulseStream : out  STD_LOGIC);
end dac8;

architecture Behavioral of dac8 is
  signal sum : STD_LOGIC_VECTOR (8 downto 0);
begin
  PulseStream <= sum(8);
			
  process (clk, sum)
  begin
    if Clk'Event and Clk = '1' then
      if Reset = '1' then
        sum <= "010000000";
      else
        sum <= ("0" & sum(7 downto 0)) + ("0" &data);
      end if;
    end if;
  end process;
end Behavioral;


Hints and tips

You can get the raw sample data from an 8 bit WAV file. Just use "dd" to lop off the first 44 bytes of the file, then dump the reaming bytes as character values. The samples should be 8 bit unsigned values - graph them in a spreadsheet to check that they look sensible. If they are not unsigned values either just add 128 to the values before you use them, or alternatively just flip data(7).

Personal tools