projects/nexys2_host_controller/host/stm
projects/nexys2_host_controller/host/stm_test
-# Test audio files
+# Test audio files, because copyright law is important to me
*.wav
+*.mp3
+*.jnk
.idea/
+__pycache__/
samp_b_l <= signed(b_dat_i(15 downto 0));
samp_b_r <= signed(b_dat_i(31 downto 16));
- result_l <= samp_a_l + samp_b_l;
- result_r <= samp_a_r + samp_b_r;
+ result_l <= (samp_a_l(15) & samp_a_l) + ((samp_b_l(15)) & samp_b_l);
+ result_r <= (samp_a_r(15) & samp_a_r) + ((samp_b_r(15)) & samp_b_r);
e_sat_l: entity work.saturate
generic map (WIDTH_IN => 17, WIDTH_OUT => 16)
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+
+
+entity pcm16_2ch_tapeeffect is
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ en_rolloff: in std_logic;
+ en_flutter: in std_logic;
+ en_wow: in std_logic;
+ en_noise: in std_logic;
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ dat_i: in std_logic_vector(31 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector(31 downto 0)
+ );
+end pcm16_2ch_tapeeffect;
+
+
+architecture behavioral of pcm16_2ch_tapeeffect is
+
+ -- Stage 1 - High frequency rolloff
+
+ signal split_a_stb: std_logic;
+ signal split_a_rdy: std_logic;
+ signal split_b_stb: std_logic;
+ signal split_b_rdy: std_logic;
+ signal split_dat: std_logic_vector(31 downto 0);
+
+ signal filter_stb: std_logic;
+ signal filter_rdy: std_logic;
+ signal filter_dat: std_logic_vector(31 downto 0);
+
+ signal bypass_stb: std_logic;
+ signal bypass_rdy: std_logic;
+ signal bypass_dat: std_logic_vector(31 downto 0);
+
+ signal merge_stb: std_logic;
+ signal merge_rdy: std_logic;
+ signal merge_dat: std_logic_vector(31 downto 0);
+
+ signal stage1_stb: std_logic;
+ signal stage1_rdy: std_logic;
+ signal stage1_dat: std_logic_vector(31 downto 0);
+
+ -- Stage 2 - Wow and flutter
+
+ constant FLUTTER_WIDTH: integer := 9;
+ constant FLUTTER_INC: std_logic_vector(15 downto 0) := "00000000"&"00100000";
+ signal flutter_stb: std_logic;
+ signal flutter_rdy: std_logic;
+ signal flutter_dat: std_logic_vector(FLUTTER_WIDTH-1 downto 0);
+
+ signal delay_dat: std_logic_vector(9 downto 0);
+
+ signal stage2_stb: std_logic;
+ signal stage2_rdy: std_logic;
+ signal stage2_dat: std_logic_vector(31 downto 0);
+
+ -- Stage 3 - Hiss
+
+ signal noise_stb: std_logic;
+ signal noise_rdy: std_logic;
+ signal noise_raw: std_logic_vector( 9 downto 0);
+ signal noise_dat: std_logic_vector(31 downto 0);
+
+begin
+
+ ----------------------------------------------------------------------------
+ -- Low pass filter the audio stream
+
+ e_split: entity work.pipectrl_split
+ generic map (WIDTH => 32)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ stb_i => stb_i,
+ rdy_o => rdy_o,
+ dat_i => dat_i,
+
+ a_stb_o => split_a_stb,
+ a_rdy_i => split_a_rdy,
+
+ b_stb_o => split_b_stb,
+ b_rdy_i => split_b_rdy,
+
+ dat_o => split_dat
+ );
+
+ e_filter: entity work.pcm16_2ch_windowsum
+ generic map (WINDOW => 16)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ stb_i => split_a_stb,
+ rdy_o => split_a_rdy,
+ dat_i => split_dat,
+
+ stb_o => filter_stb,
+ rdy_i => filter_rdy,
+ dat_o => filter_dat
+ );
+
+ e_bypass: entity work.pipectrl
+ generic map (WIDTH => 32)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ stb_i => split_b_stb,
+ rdy_o => split_b_rdy,
+ dat_i => split_dat,
+
+ stb_o => bypass_stb,
+ rdy_i => bypass_rdy,
+ dat_o => bypass_dat
+ );
+
+ e_filter_merge: entity work.merge
+ port map (
+ a_stb_i => filter_stb,
+ a_rdy_o => filter_rdy,
+
+ b_stb_i => bypass_stb,
+ b_rdy_o => bypass_rdy,
+
+ stb_o => merge_stb,
+ rdy_i => merge_rdy
+ );
+ merge_dat <= filter_dat when en_rolloff = '1' else bypass_dat;
+
+ e_filter_ctrl: entity work.pipectrl
+ generic map (WIDTH => 32)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ stb_i => merge_stb,
+ rdy_o => merge_rdy,
+ dat_i => merge_dat,
+
+ stb_o => stage1_stb,
+ rdy_i => stage1_rdy,
+ dat_o => stage1_dat
+ );
+
+ ----------------------------------------------------------------------------
+ -- Variable delay for wow and flutter
+
+ e_flutter: entity work.src_fracstep
+ generic map (WIDTH_OUT => FLUTTER_WIDTH)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ inc_i => std_logic_vector(unsigned(FLUTTER_INC)),
+
+ stb_o => flutter_stb,
+ rdy_i => flutter_rdy,
+ dat_o => flutter_dat
+ );
+
+ delay_dat <= std_logic_vector(resize(unsigned(flutter_dat), 10)) when en_flutter = '1' else (others => '0');
+
+ e_vardelay: entity work.pcm16_2ch_vardelay
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ delay_stb_i => flutter_stb,
+ delay_rdy_o => flutter_rdy,
+ delay_dat_i => delay_dat,
+
+ audio_stb_i => stage1_stb,
+ audio_rdy_o => stage1_rdy,
+ audio_dat_i => stage1_dat,
+
+ stb_o => stage2_stb,
+ rdy_i => stage2_rdy,
+ dat_o => stage2_dat
+ );
+
+ ----------------------------------------------------------------------------
+ -- Add noise stream to audio stream
+
+ e_noise: entity work.src_noise
+ generic map (WIDTH => 10)
+ port map (
+ clk_i => clk_i,
+
+ stb_o => noise_stb,
+ rdy_i => noise_rdy,
+ dat_o => noise_raw
+ );
+
+ noise_dat <= std_logic_vector(resize(signed(noise_raw), 16)) &
+ std_logic_vector(resize(signed(noise_raw), 16)) when en_noise = '1' else (others => '0');
+
+ e_sum: entity work.pcm16_2ch_sum
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ a_stb_i => stage2_stb,
+ a_rdy_o => stage2_rdy,
+ a_dat_i => stage2_dat,
+
+ b_stb_i => noise_stb,
+ b_rdy_o => noise_rdy,
+ b_dat_i => noise_dat,
+
+ stb_o => stb_o,
+ rdy_i => rdy_i,
+ dat_o => dat_o
+ );
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library work;
+
+
+entity pcm16_2ch_vardelay is
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ delay_stb_i: in std_logic;
+ delay_rdy_o: out std_logic;
+ delay_dat_i: in std_logic_vector(9 downto 0);
+
+ audio_stb_i: in std_logic;
+ audio_rdy_o: out std_logic;
+ audio_dat_i: in std_logic_vector(31 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector(31 downto 0)
+ );
+end pcm16_2ch_vardelay;
+
+
+architecture behavioral of pcm16_2ch_vardelay is
+
+ constant COUNT_WIDTH: integer := 10;
+
+ signal en: std_logic;
+ signal stb: std_logic;
+ signal rdy: std_logic;
+
+ signal samp_l: std_logic_vector(15 downto 0);
+ signal samp_r: std_logic_vector(15 downto 0);
+
+ signal result_l: std_logic_vector(15 downto 0);
+ signal result_r: std_logic_vector(15 downto 0);
+
+ signal ptr_head_reg: unsigned(COUNT_WIDTH-1 downto 0) := (others => '0');
+ signal ptr_tail: unsigned(COUNT_WIDTH-1 downto 0);
+
+begin
+
+ e_merge: entity work.merge
+ port map (
+ a_stb_i => delay_stb_i,
+ a_rdy_o => delay_rdy_o,
+ b_stb_i => audio_stb_i,
+ b_rdy_o => audio_rdy_o,
+ stb_o => stb,
+ rdy_i => rdy
+ );
+
+ e_ctrl: entity work.pipectrl
+ generic map (WIDTH => 0)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ en_o => en,
+ stb_i => stb,
+ rdy_o => rdy,
+ dat_i => open,
+ stb_o => stb_o,
+ rdy_i => rdy_i,
+ dat_o => open
+ );
+
+ process (rst_i, clk_i, en, ptr_head_reg)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ -- Probably don't need reset logic
+ elsif en = '1' then
+ ptr_head_reg <= ptr_head_reg + 1;
+ end if;
+ end if;
+ end process;
+
+ samp_l <= audio_dat_i(15 downto 0);
+ samp_r <= audio_dat_i(31 downto 16);
+
+ ptr_tail <= (ptr_head_reg - unsigned(delay_dat_i)) - 1;
+
+ e_fifo_l: ramb16_s18_s18
+ port map (
+ -- Head port (insertion)
+ WEA => '1',
+ ENA => en,
+ SSRA => '0',
+ CLKA => clk_i,
+ ADDRA => std_logic_vector(ptr_head_reg),
+ DIA => samp_l,
+ DIPA => (others => '0'),
+
+ DOA => open,
+ DOPA => open,
+
+ -- Tail port (removal)
+ WEB => '0',
+ ENB => en,
+ SSRB => '0',
+ CLKB => clk_i,
+ ADDRB => std_logic_vector(ptr_tail),
+ DIB => (others => '0'),
+ DIPB => (others => '0'),
+
+ DOB => result_l,
+ DOPB => open
+ );
+
+ e_fifo_r: ramb16_s18_s18
+ port map (
+ -- Head port (insertion)
+ WEA => '1',
+ ENA => en,
+ SSRA => '0',
+ CLKA => clk_i,
+ ADDRA => std_logic_vector(ptr_head_reg),
+ DIA => samp_r,
+ DIPA => (others => '0'),
+
+ DOA => open,
+ DOPA => open,
+
+ -- Tail port (removal)
+ WEB => '0',
+ ENB => en,
+ SSRB => '0',
+ CLKB => clk_i,
+ ADDRB => std_logic_vector(ptr_tail),
+ DIB => (others => '0'),
+ DIPB => (others => '0'),
+
+ DOB => result_r,
+ DOPB => open
+ );
+
+ dat_o <= result_r & result_l;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.math_real.all;
+
+library work;
+
+
+entity pcm16_2ch_windowsum is
+ generic (
+ WINDOW: positive := 16
+ );
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ dat_i: in std_logic_vector(31 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector(31 downto 0)
+ );
+end pcm16_2ch_windowsum;
+
+
+architecture behavioral of pcm16_2ch_windowsum is
+
+ constant FILT_WIDTH: positive := 16+integer(ceil(log2(real(WINDOW))));
+
+ signal en: std_logic;
+
+ signal samp_l: std_logic_vector(15 downto 0);
+ signal samp_r: std_logic_vector(15 downto 0);
+
+ signal filt_l: std_logic_vector(FILT_WIDTH-1 downto 0);
+ signal filt_r: std_logic_vector(FILT_WIDTH-1 downto 0);
+
+ signal result_l: std_logic_vector(15 downto 0);
+ signal result_r: std_logic_vector(15 downto 0);
+
+begin
+
+ e_ctrl: entity work.pipectrl
+ generic map (WIDTH => 0)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ en_o => en,
+ stb_i => stb_i,
+ rdy_o => rdy_o,
+ dat_i => open,
+ stb_o => stb_o,
+ rdy_i => rdy_i,
+ dat_o => open
+ );
+
+ samp_l <= dat_i(15 downto 0);
+ samp_r <= dat_i(31 downto 16);
+
+ e_filter_l: entity work.filter_windowsum
+ generic map (
+ WIDTH => 16,
+ WINDOW => WINDOW
+ )
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ en_i => en,
+
+ dat_i => samp_l,
+ dat_o => filt_l
+ );
+
+ e_filter_r: entity work.filter_windowsum
+ generic map (
+ WIDTH => 16,
+ WINDOW => WINDOW
+ )
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ en_i => en,
+
+ dat_i => samp_r,
+ dat_o => filt_r
+ );
+
+ result_l <= filt_l(FILT_WIDTH-1 downto FILT_WIDTH-16);
+ result_r <= filt_r(FILT_WIDTH-1 downto FILT_WIDTH-16);
+
+ dat_o <= result_r & result_l;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use ieee.math_real.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity table_sine_1k_16 is
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ en: in std_logic;
+
+ adr_i: in std_logic_vector(9 downto 0);
+ dat_o: out std_logic_vector(15 downto 0)
+ );
+end table_sine_1k_16;
+
+
+architecture behavioral of table_sine_1k_16 is
+begin
+
+ e_table: ramb16_s18
+ generic map (
+ INIT_00 = x"0bc30afb0a32096a08a107d907100647057e04b603ed0324025b019200c90000",
+ INIT_01 = x"1833176d16a715e1151b1455138e12c71200113910720fab0ee30e1b0d530c8b",
+ INIT_02 = x"246723a622e422232161209f1fdc1f191e561d931ccf1c0b1b461a8219bd18f8",
+ INIT_03 = x"30412f862ecc2e102d542c982bdb2b1e2a6129a328e52826276726a725e72527",
+ INIT_04 = x"3ba43af23a3f398c38d83824376f36b93603354d349633de3326326d31b430fb",
+ INIT_05 = x"467445cc4523447a43d04325427941cd412040733fc53f163e673db73d073c56",
+ INIT_06 = x"50974ffa4f5d4ebf4e204d804ce04c3f4b9d4afa4a5749b3490e486947c3471c",
+ INIT_07 = x"59f3596358d3584257b0571d568955f4555f54c95432539a5301526851ce5133",
+ INIT_08 = x"627161f0616e60eb60675fe25f5d5ed65e4f5dc65d3d5cb35c285b9c5b0f5a81",
+ INIT_09 = x"69fc698b691968a5683167bc674566ce665665dd656264e7646b63ee637062f1",
+ INIT_0a = x"708270226fc06f5e6efa6e956e306dc96d616cf86c8e6c236bb76b4a6adb6a6c",
+ INIT_0b = x"75f375a47554750374b1745e740a73b5735e730672ae725471f9719d714070e1",
+ INIT_0c = x"7a417a0479c779897949790878c67883783f77f977b3776b772276d8768d7640",
+ INIT_0d = x"7d617d387d0e7ce27cb67c887c597c297bf77bc47b917b5c7b257aee7ab57a7c",
+ INIT_0e = x"7f4c7f377f207f087eef7ed47eb97e9c7e7e7e5e7e3e7e1c7df97dd57db07d89",
+ INIT_0f = x"7ffe7ffc7ff97ff57fef7fe87fe07fd77fcd7fc17fb47fa67f967f867f747f61",
+ INIT_10 = x"7f747f867f967fa67fb47fc17fcd7fd77fe07fe87fef7ff57ff97ffc7ffe7fff",
+ INIT_11 = x"7db07dd57df97e1c7e3e7e5e7e7e7e9c7eb97ed47eef7f087f207f377f4c7f61",
+ INIT_12 = x"7ab57aee7b257b5c7b917bc47bf77c297c597c887cb67ce27d0e7d387d617d89",
+ INIT_13 = x"768d76d87722776b77b377f9783f788378c679087949798979c77a047a417a7c",
+ INIT_14 = x"7140719d71f9725472ae7306735e73b5740a745e74b17503755475a475f37640",
+ INIT_15 = x"6adb6b4a6bb76c236c8e6cf86d616dc96e306e956efa6f5e6fc07022708270e1",
+ INIT_16 = x"637063ee646b64e7656265dd665666ce674567bc683168a56919698b69fc6a6c",
+ INIT_17 = x"5b0f5b9c5c285cb35d3d5dc65e4f5ed65f5d5fe2606760eb616e61f0627162f1",
+ INIT_18 = x"51ce52685301539a543254c9555f55f45689571d57b0584258d3596359f35a81",
+ INIT_19 = x"47c34869490e49b34a574afa4b9d4c3f4ce04d804e204ebf4f5d4ffa50975133",
+ INIT_1a = x"3d073db73e673f163fc54073412041cd4279432543d0447a452345cc4674471c",
+ INIT_1b = x"31b4326d332633de3496354d360336b9376f382438d8398c3a3f3af23ba43c56",
+ INIT_1c = x"25e726a72767282628e529a32a612b1e2bdb2c982d542e102ecc2f86304130fb",
+ INIT_1d = x"19bd1a821b461c0b1ccf1d931e561f191fdc209f2161222322e423a624672527",
+ INIT_1e = x"0d530e1b0ee30fab10721139120012c7138e1455151b15e116a7176d183318f8",
+ INIT_1f = x"00c90192025b032403ed04b6057e0647071007d908a1096a0a320afb0bc30c8b",
+ INIT_20 = x"f43df505f5cef696f75ff827f8f0f9b9fa82fb4afc13fcdcfda5fe6eff370000",
+ INIT_21 = x"e7cde893e959ea1feae5ebabec72ed39ee00eec7ef8ef055f11df1e5f2adf375",
+ INIT_22 = x"db99dc5add1cddddde9fdf61e024e0e7e1aae26de331e3f5e4bae57ee643e708",
+ INIT_23 = x"cfbfd07ad134d1f0d2acd368d425d4e2d59fd65dd71bd7dad899d959da19dad9",
+ INIT_24 = x"c45cc50ec5c1c674c728c7dcc891c947c9fdcab3cb6acc22ccdacd93ce4ccf05",
+ INIT_25 = x"b98cba34baddbb86bc30bcdbbd87be33bee0bf8dc03bc0eac199c249c2f9c3aa",
+ INIT_26 = x"af69b006b0a3b141b1e0b280b320b3c1b463b506b5a9b64db6f2b797b83db8e4",
+ INIT_27 = x"a60da69da72da7bea850a8e3a977aa0caaa1ab37abceac66acffad98ae32aecd",
+ INIT_28 = x"9d8f9e109e929f159f99a01ea0a3a12aa1b1a23aa2c3a34da3d8a464a4f1a57f",
+ INIT_29 = x"9604967596e7975b97cf984498bb993299aa9a239a9e9b199b959c129c909d0f",
+ INIT_2a = x"8f7e8fde904090a29106916b91d09237929f9308937293dd944994b695259594",
+ INIT_2b = x"8a0d8a5c8aac8afd8b4f8ba28bf68c4b8ca28cfa8d528dac8e078e638ec08f1f",
+ INIT_2c = x"85bf85fc8639867786b786f8873a877d87c18807884d889588de8928897389c0",
+ INIT_2d = x"829f82c882f2831e834a837883a783d78409843c846f84a484db8512854b8584",
+ INIT_2e = x"80b480c980e080f88111812c81478164818281a281c281e48207822b82508277",
+ INIT_2f = x"800280048007800b80118018802080298033803f804c805a806a807a808c809f",
+ INIT_30 = x"808c807a806a805a804c803f80338029802080188011800b8007800480028001",
+ INIT_31 = x"8250822b820781e481c281a2818281648147812c811180f880e080c980b4809f",
+ INIT_32 = x"854b851284db84a4846f843c840983d783a78378834a831e82f282c8829f8277",
+ INIT_33 = x"8973892888de8895884d880787c1877d873a86f886b78677863985fc85bf8584",
+ INIT_34 = x"8ec08e638e078dac8d528cfa8ca28c4b8bf68ba28b4f8afd8aac8a5c8a0d89c0",
+ INIT_35 = x"952594b6944993dd93729308929f923791d0916b910690a290408fde8f7e8f1f",
+ INIT_36 = x"9c909c129b959b199a9e9a2399aa993298bb984497cf975b96e7967596049594",
+ INIT_37 = x"a4f1a464a3d8a34da2c3a23aa1b1a12aa0a3a01e9f999f159e929e109d8f9d0f",
+ INIT_38 = x"ae32ad98acffac66abceab37aaa1aa0ca977a8e3a850a7bea72da69da60da57f",
+ INIT_39 = x"b83db797b6f2b64db5a9b506b463b3c1b320b280b1e0b141b0a3b006af69aecd",
+ INIT_3a = x"c2f9c249c199c0eac03bbf8dbee0be33bd87bcdbbc30bb86baddba34b98cb8e4",
+ INIT_3b = x"ce4ccd93ccdacc22cb6acab3c9fdc947c891c7dcc728c674c5c1c50ec45cc3aa",
+ INIT_3c = x"da19d959d899d7dad71bd65dd59fd4e2d425d368d2acd1f0d134d07acfbfcf05",
+ INIT_3d = x"e643e57ee4bae3f5e331e26de1aae0e7e024df61de9fdddddd1cdc5adb99dad9",
+ INIT_3e = x"f2adf1e5f11df055ef8eeec7ee00ed39ec72ebabeae5ea1fe959e893e7cde708",
+ INIT_3f = x"ff37fe6efda5fcdcfc13fb4afa82f9b9f8f0f827f75ff696f5cef505f43df375"
+ )
+ port map (
+ WE => '0',
+ EN => en,
+ SSR => rst_i,
+ CLK => clk_i,
+ ADDR => adr_i,
+ DI => (others => '0'),
+ DIP => (others => '0'),
+ DOP => open,
+ DO => dat_o
+ );
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+library utility;
+library dsp;
+library nexys2_lib;
+
+
+entity nexys2 is
+ port (
+ clk_50: in std_logic;
+
+ EppDB_DstmDB: inout std_logic_vector(7 downto 0);
+ EppWRITE: in std_logic;
+ EppASTB_DstmFLAGA: in std_logic;
+ EppDSTB_DstmFLAGB: in std_logic;
+ EppWAIT_DstmSLRD: out std_logic;
+ DstmIFCLK: in std_logic;
+ DstmSLCS: in std_logic;
+ DstmADR: out std_logic_vector(1 downto 0);
+ DstmSLWR: out std_logic;
+ DstmSLOE: out std_logic;
+ DstmPKTEND: out std_logic;
+ UsbMode: in std_logic;
+ UsbRdy: in std_logic;
+
+ seg: out std_logic_vector(6 downto 0);
+ dp: out std_logic;
+ an: out std_logic_vector(3 downto 0);
+ Led: out std_logic_vector(7 downto 0);
+ sw: in std_logic_vector(7 downto 0);
+
+ JA: inout std_logic_vector(7 downto 0)
+ );
+end nexys2;
+
+
+architecture behavioral of nexys2 is
+
+ signal rst_50: std_logic; -- Reset within clk_50 domain
+
+ -- USB interfaces
+ signal wb_cyc: std_logic;
+ signal wb_stb: std_logic;
+ signal wb_we: std_logic;
+ signal wb_ack: std_logic;
+ signal wb_adr: std_logic_vector(7 downto 0);
+ signal wb_miso: std_logic_vector(7 downto 0);
+ signal wb_mosi: std_logic_vector(7 downto 0);
+
+ signal dl_stb: std_logic;
+ signal dl_rdy: std_logic;
+ signal dl_dat: std_logic_vector(7 downto 0);
+ signal ul_stb: std_logic;
+ signal ul_rdy: std_logic;
+ signal ul_dat: std_logic_vector(7 downto 0);
+
+ -- I2S interface
+ signal i2s_rx_l_dat: std_logic_vector(23 downto 0);
+ signal i2s_rx_r_dat: std_logic_vector(23 downto 0);
+ signal i2s_tx_l_dat: std_logic_vector(23 downto 0);
+ signal i2s_tx_r_dat: std_logic_vector(23 downto 0);
+
+ -- Control signals
+ signal debug_to_host: std_logic_vector(63 downto 0);
+ signal debug_from_host: std_logic_vector(63 downto 0);
+
+ -- Audio pipelines
+ signal audio_dl_stb: std_logic;
+ signal audio_dl_rdy: std_logic;
+ signal audio_dl_dat: std_logic_vector(31 downto 0);
+
+ signal audio_ul_stb: std_logic;
+ signal audio_ul_rdy: std_logic;
+ signal audio_ul_dat: std_logic_vector(31 downto 0);
+
+ signal audio_i_stb: std_logic;
+ signal audio_i_rdy: std_logic;
+ signal audio_i_dat: std_logic_vector(31 downto 0);
+
+ signal audio_o_stb: std_logic;
+ signal audio_o_rdy: std_logic;
+ signal audio_o_dat: std_logic_vector(31 downto 0);
+
+begin
+
+ seg <= (others => '1');
+ dp <= '1';
+ an <= (others => '1');
+ Led <= (others => '0');
+
+ ----------------------------------------------------------------------------
+ -- Processing pipeline
+
+ e_effect: entity dsp.pcm16_2ch_tapeeffect
+ port map (
+ rst_i => rst_50,
+ clk_i => clk_50,
+
+ en_rolloff => sw(0),
+ en_flutter => sw(1),
+ en_wow => sw(2),
+ en_noise => sw(3),
+
+ stb_i => audio_dl_stb,
+ rdy_o => audio_dl_rdy,
+ dat_i => audio_dl_dat,
+
+ stb_o => audio_o_stb,
+ rdy_i => audio_o_rdy,
+ dat_o => audio_o_dat
+ );
+
+ audio_ul_stb <= audio_i_stb;
+ audio_ul_rdy <= audio_i_rdy;
+ audio_ul_dat <= audio_i_dat;
+
+
+ ----------------------------------------------------------------------------
+ -- USB interfaces
+
+ e_por_clk50: entity utility.power_on_reset_opt
+ port map (
+ rst_i => '0',
+ clk_i => clk_50,
+ rst_o => rst_50
+ );
+
+ e_usb: entity nexys2_lib.usb
+ port map (
+ rst_i => rst_50,
+
+ EppDB_DstmDB => EppDB_DstmDB,
+ EppWRITE => EppWRITE,
+ EppASTB_DstmFLAGA => EppASTB_DstmFLAGA,
+ EppDSTB_DstmFLAGB => EppDSTB_DstmFLAGB,
+ EppWAIT_DstmSLRD => EppWAIT_DstmSLRD,
+ DstmIFCLK => DstmIFCLK,
+ DstmSLCS => DstmSLCS,
+ DstmADR => DstmADR,
+ DstmSLWR => DstmSLWR,
+ DstmSLOE => DstmSLOE,
+ DstmPKTEND => DstmPKTEND,
+ UsbMode => UsbMode,
+ UsbRdy => UsbRdy,
+
+ epp_clk_i => clk_50,
+ epp_cyc_o => wb_cyc,
+ epp_stb_o => wb_stb,
+ epp_we_o => wb_we,
+ epp_ack_i => wb_ack,
+ epp_adr_o => wb_adr,
+ epp_dat_i => wb_miso,
+ epp_dat_o => wb_mosi,
+
+ stm_clk_i => clk_50,
+ stm_dl_stb_o => dl_stb,
+ stm_dl_ack_i => dl_rdy,
+ stm_dl_dat_o => dl_dat,
+ stm_ul_stb_i => ul_stb,
+ stm_ul_ack_o => ul_rdy,
+ stm_ul_dat_i => ul_dat
+ );
+
+ e_debug: entity utility.wb_debug
+ port map (
+ rst_i => rst_50,
+ clk_i => clk_50,
+
+ cyc_i => wb_cyc,
+ stb_i => wb_stb,
+ we_i => wb_we,
+ ack_o => wb_ack,
+ adr_i => wb_adr(2 downto 0),
+ dat_i => wb_mosi,
+ dat_o => wb_miso,
+
+ debug_i => debug_to_host,
+ debug_o => debug_from_host
+ );
+
+ e_deser: entity dsp.deserialize
+ generic map (WIDTH => 8, N => 4)
+ port map (
+ rst_i => rst_50,
+ clk_i => clk_50,
+
+ stb_i => dl_stb,
+ rdy_o => dl_rdy,
+ dat_i => dl_dat,
+
+ stb_o => audio_dl_stb,
+ rdy_i => audio_dl_rdy,
+ dat_o => audio_dl_dat
+ );
+
+ e_ser: entity dsp.serialize
+ generic map (WIDTH => 8, N => 4)
+ port map (
+ rst_i => rst_50,
+ clk_i => clk_50,
+
+ stb_i => audio_ul_stb,
+ rdy_o => audio_ul_rdy,
+ dat_i => audio_ul_dat,
+
+ stb_o => ul_stb,
+ rdy_i => ul_rdy,
+ dat_o => ul_dat
+ );
+
+
+ ----------------------------------------------------------------------------
+ -- I2S interface
+
+ e_i2s_pmod: entity dsp.i2s_pmod
+ port map (
+ rst_50 => rst_50,
+ clk_50 => clk_50,
+
+ stb_i => audio_o_stb,
+ rdy_o => audio_o_rdy,
+ l_dat_i => i2s_tx_l_dat,
+ r_dat_i => i2s_tx_r_dat,
+
+ stb_o => audio_i_stb,
+ rdy_i => audio_i_rdy,
+ l_dat_o => i2s_rx_l_dat,
+ r_dat_o => i2s_rx_r_dat,
+
+ pmod => JA
+ );
+ i2s_tx_r_dat <= audio_o_dat(31 downto 16) & x"00";
+ i2s_tx_l_dat <= audio_o_dat(15 downto 0) & x"00";
+ audio_i_dat <= i2s_rx_r_dat(23 downto 8) & i2s_rx_l_dat(23 downto 8);
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+library dsp;
+
+
+entity test_tapeeffect is
+end test_tapeeffect;
+
+
+architecture behavior of test_tapeeffect is
+
+ constant CLK_I_PERIOD: time := 20 ns;
+
+ signal rst_i: std_logic;
+ signal clk_i: std_logic;
+
+ signal stb_i: std_logic;
+ signal rdy_o: std_logic;
+ signal dat_i: std_logic_vector(31 downto 0);
+
+ signal stb_o: std_logic;
+ signal rdy_i: std_logic;
+ signal dat_o: std_logic_vector(31 downto 0);
+
+begin
+
+ p_test: process
+ begin
+ -- Initial values
+ stb_i <= '0';
+ rdy_i <= '1';
+
+ -- Reset
+ rst_i <= '1';
+ wait for CLK_I_PERIOD*17;
+ rst_i <= '0';
+
+ -- Test
+
+ -- Done
+ wait;
+ end process;
+
+ e_uut: entity dsp.pcm16_2ch_tapeeffect
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ en_rolloff => '0',
+ en_flutter => '0',
+ en_wow => '0',
+ en_noise => '1',
+
+ stb_i => stb_i,
+ rdy_o => rdy_o,
+ dat_i => dat_i,
+
+ stb_o => stb_o,
+ rdy_i => rdy_i,
+ dat_o => dat_o
+ );
+
+ p_clk: process
+ begin
+ clk_i <= '0';
+ wait for CLK_I_PERIOD/2;
+ clk_i <= '1';
+ wait for CLK_I_PERIOD/2;
+ end process;
+
+end;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+library simulated;
+library work;
+
+
+entity test_nexys2 is
+end test_nexys2;
+
+
+architecture behavior of test_nexys2 is
+
+ constant CLK_50_PERIOD: time := 20 ns;
+
+ signal clk_50: std_logic;
+
+ signal ifclk: std_logic;
+ signal slcs: std_logic;
+ signal flaga: std_logic;
+ signal flagb: std_logic;
+ signal slrd: std_logic;
+ signal slwr: std_logic;
+ signal sloe: std_logic;
+ signal pktend: std_logic;
+ signal fifoadr: std_logic_vector(1 downto 0);
+ signal db: std_logic_vector(7 downto 0);
+
+ signal host_dl_data: std_logic_vector(7 downto 0);
+ signal host_ul_count: integer;
+
+ signal sw: std_logic_vector(7 downto 0);
+ signal JA: std_logic_vector(7 downto 0);
+
+begin
+
+ p_test: process
+ begin
+ sw(7 downto 0) <= (others => '0');
+ sw(3) <= '1'; -- Enable noise
+ wait;
+ end process;
+
+
+ e_uut: entity work.nexys2
+ port map (
+ clk_50 => clk_50,
+ EppDB_DstmDB => db,
+ EppWRITE => '1',
+ EppASTB_DstmFLAGA => flaga,
+ EppDSTB_DstmFLAGB => flagb,
+ EppWAIT_DstmSLRD => slrd,
+ DstmIFCLK => ifclk,
+ DstmSLCS => slcs,
+ DstmADR => fifoadr,
+ DstmSLWR => slwr,
+ DstmSLOE => sloe,
+ DstmPKTEND => pktend,
+ UsbMode => '0',
+ UsbRdy => '1',
+ seg => open,
+ dp => open,
+ an => open,
+ Led => open,
+ sw => sw,
+ JA => JA
+ );
+
+
+ e_stm: entity simulated.stmhost
+ port map (
+ ifclk => ifclk,
+ slcs => slcs,
+ flaga => flaga,
+ flagb => flagb,
+ slrd => slrd,
+ slwr => slwr,
+ sloe => sloe,
+ pktend => pktend,
+ fifoadr => fifoadr,
+ db => db,
+
+ host_dl_data => host_dl_data,
+ host_ul_count => host_ul_count
+ );
+
+
+ e_i2s: entity simulated.proto_i2s_tx
+ port map (
+ sck => JA(6),
+ ws => JA(5),
+ sd => JA(7)
+ );
+
+
+ p_clk_50: process
+ begin
+ clk_50 <= '0';
+ wait for CLK_50_PERIOD/2;
+ clk_50 <= '1';
+ wait for CLK_50_PERIOD/2;
+ end process;
+
+end;
--- /dev/null
+#!/usr/bin/env python3
+
+from __future__ import annotations
+from typing import *
+
+import math
+from numpy.fft import fft, ifft
+
+# ------------------------------------------------------------------------------
+
+
+class C(object):
+ def __init__(self, r: float, i: float):
+ self.r, self.i = r, i
+
+ def __add__(self, other: C):
+ if isinstance(other, int) or isinstance(other, float):
+ other = C(other, 0)
+ return C(self.r+other.r, self.i+other.i)
+
+ def __neg__(self):
+ return C(-self.r, -self.i)
+
+ def __sub__(self, other):
+ if isinstance(other, int) or isinstance(other, float):
+ other = C(other, 0)
+ return C(self.r-other.r, self.i-other.i)
+
+ def __mul__(self, other):
+ if isinstance(other, int) or isinstance(other, float):
+ other = C(other, 0)
+ return C(self.r*other.r - self.i*other.i, self.r*other.i + self.i*other.r)
+
+ def magnitude(self):
+ return math.sqrt(self.r*self.r + self.i*self.i)
+
+ def __str__(self):
+ return f'{self.r:7.3f} + {self.i:7.3f}i'
+
+ def __repr__(self):
+ return str(self)
+
+ @staticmethod
+ def nth_root_of_unity(n: float):
+ # Will have one period within N samples
+ phi = 2*math.pi/n
+ return C(math.cos(phi), math.sin(phi))
+
+
+# ------------------------------------------------------------------------------
+# Examples from:
+# https://www.youtube.com/watch?v=h7apO7q16V0
+
+
+def mul_poly(poly_coef_a: List[int], poly_coef_b: List[int]) -> List[int]:
+ """O(N^2) algorithm to multiply polynomials in coefficient form (functionally, a convolution)"""
+ poly_coef_c = [0] * (len(poly_coef_a)+len(poly_coef_b)-1)
+ for i, coef_a in enumerate(poly_coef_a):
+ for j, coef_b in enumerate(poly_coef_b):
+ poly_coef_c[i+j] += coef_a*coef_b
+ return poly_coef_c
+
+
+def eval_poly(coef: List[C], x: C) -> C:
+ xn = C(1, 0)
+ p = C(0, 0)
+ for c in coef:
+ p += c * xn
+ xn *= x
+ return p
+
+
+def dft_naive(coef: List[C]) -> List[C]:
+ out = list()
+ n = len(coef)
+ n2 = int(n/2)
+ for k in range(n): # Number of periods
+ e = C(0, 0) # Evaluated polynomial at x = nru
+ for i in range(n): # Sample index
+ phi = -2*math.pi*k*i/n
+
+ # principal-nth-root-of-unity-with-k-periods-within-n-samples to the power of i
+ # k/n-th root of unity?
+ im = math.sin(phi)
+ re = math.cos(phi)
+ nru = C(re, im) # principal-nth-root-of-unity to the power of i
+ e += coef[i] * nru
+ out.append(e)
+ return out
+
+
+def fft_recursive(coef: List[C]) -> List[C]:
+ n = len(coef)
+ if n <= 1:
+ return coef
+ n2 = int(n/2)
+
+ coef_even = coef[0::2]
+ coef_odd = coef[1::2]
+
+ even = fft_recursive(coef_even)
+ odd = fft_recursive(coef_odd)
+
+ out = [C(0,0)]*n
+ for k in range(n2):
+ phi = -2*math.pi*k/n
+ re = math.cos(phi)
+ im = math.sin(phi)
+ w = C(re, im)
+
+ out[k] = even[k] + w*odd[k]
+ out[k+n2] = even[k] - w*odd[k]
+
+ return out
+
+
+def ifft_recursive(coef: List[C]) -> List[C]:
+ n = len(coef)
+ if n <= 1:
+ return coef
+ n2 = int(n/2)
+
+ coef_even = coef[0::2]
+ coef_odd = coef[1::2]
+
+ even = ifft_recursive(coef_even)
+ odd = ifft_recursive(coef_odd)
+
+ out = [C(0,0)]*n
+ for k in range(n2):
+ phi = 2*math.pi*k/n
+ re = math.cos(phi)
+ im = math.sin(phi)
+ w = C(re, im)
+
+ out[k] = (even[k] + w*odd[k]) * 0.5
+ out[k+n2] = (even[k] - w*odd[k]) * 0.5
+
+ return out
+
+
+def reorder(c: List[Any]) -> List[Any]:
+ if len(c) <= 1:
+ return c
+ return reorder(c[0::2]) + reorder(c[1::2])
+
+
+def fft_iter(coef: List[C]) -> List[Any]:
+ coef = reorder(coef) # Pretend this isn't recursive, or that we did it ahead of time
+ # On an FPGA, the reordering can be done by reversing the bits of the index while storing into a buffer
+ n = len(coef)
+
+ phis = [-2*math.pi*k/n for k in range(n)]
+ res = [math.cos(phi) for phi in phis]
+ ims = [math.sin(phi) for phi in phis]
+ ws = [C(re, im) for re, im in zip(res, ims)]
+
+ size = 2
+ while size <= n: # Each stage in the butterfly
+ s2 = int(size/2)
+ num_groups = n / size
+ for i in range(0, n, size): # Each group in the butterfly
+ for k in range(s2): # Samples within each group of the butterfly
+ a = coef[i+k]
+ b = coef[i+k+s2] * ws[int(k*num_groups)]
+ coef[i+k] = a + b
+ coef[i+k+s2] = a - b
+ size *= 2
+ return coef
+
+
+def ifft_iter(coef: List[C]) -> List[Any]:
+ coef = reorder(coef) # Pretend this isn't recursive, or that we did it ahead of time
+ # On an FPGA, the reordering can be done by reversing the bits of the index while storing into a buffer
+ n = len(coef)
+
+ phis = [2*math.pi*k/n for k in range(n)]
+ res = [math.cos(phi) for phi in phis]
+ ims = [math.sin(phi) for phi in phis]
+ ws = [C(re, im) for re, im in zip(res, ims)]
+
+ size = 2
+ while size <= n: # Each stage in the butterfly
+ s2 = int(size/2)
+ num_groups = n / size
+ for i in range(0, n, size): # Each group in the butterfly
+ for k in range(s2): # Samples within each group of the butterfly
+ a = coef[i+k]
+ b = coef[i+k+s2] * ws[int(k*num_groups)]
+ coef[i+k] = (a + b) * 0.5 # Multiplying by 1/2 a total of log2(N) times turns into multiplying by 1/N when N = 2^x
+ coef[i+k+s2] = (a - b) * 0.5
+ size *= 2
+ return coef
+
+
+# ------------------------------------------------------------------------------
+
+
+def main() -> int:
+ # A(x) = x^2 + 3x + 2, B(x) = 2x^2 + 1
+ # print(mul_poly([2, 3, 1], [1, 0, 2]))
+
+ n = 8
+
+ a = [math.cos(i*2*math.pi/n) for i in range(n)]
+ b = fft(a)
+ b = [C(i.real, i.imag) for i in b]
+ # # c = ifft(b)
+ #
+ #a2 = [C(a[i],0) for i in range(n)]
+ #a2 = [C(i,0) for i in range(n)]
+ a2 = [C(i,0) for i in [6, 2, 8, 4, 2, 8, 3, 6]]
+ b1 = dft_naive(a2)
+ b0 = fft_recursive(a2)
+ c0 = ifft_recursive(b0)
+
+ fft_iter(a2)
+
+ for i in a2:
+ print(i)
+ print()
+ print('My FFT:')
+ for i in b0:
+ print(i)
+ print()
+ print('My naive DFT:')
+ for i in b1:
+ print(i)
+ print()
+ print('"real" FFT:')
+ for i in b:
+ print(i)
+ print()
+ print('My iFFT:')
+ for i in c0:
+ print(i)
+
+ print()
+ print('Iterative FFT:')
+ b2 = fft_iter(a2)
+ for i in b2:
+ print(i)
+ print()
+ print('Iterative iFFT:')
+ c2 = ifft_iter(b2)
+ for i in c2:
+ print(i)
+
+ return 0
+
+
+if __name__ == '__main__':
+ exit(main())
--- /dev/null
+#!/usr/bin/env python3
+
+from __future__ import annotations
+from typing import *
+
+import argparse
+import struct
+
+import fft
+
+# ------------------------------------------------------------------------------
+
+
+def f_expect(f: BinaryIO, s: bytes):
+ d = f.read(len(s))
+ assert d == s
+
+
+def f_skipto(f: BinaryIO, s: bytes):
+ d = f.read(len(s))
+ while d != s:
+ d = d[1:] + f.read(1)
+
+
+def f_chomp_u32_le(f: BinaryIO):
+ return struct.unpack('<I', f.read(4))[0]
+
+
+def f_chomp_u16_le(f: BinaryIO):
+ return struct.unpack('<H', f.read(2))[0]
+
+
+def f_chomp_s16_le(f: BinaryIO):
+ return struct.unpack('<h', f.read(2))[0]
+
+
+def f_write_u32_le(f: BinaryIO, v: int):
+ f.write(struct.pack('<I', v))
+
+
+def f_write_s16_le(f: BinaryIO, v: int):
+ # Saturate, just in case
+ if v < -32768:
+ v = -32768
+ if v > 32767:
+ v = 32767
+ f.write(struct.pack('<h', v))
+
+
+def f_write_u16_le(f: BinaryIO, v: int):
+ f.write(struct.pack('<H', v&0xffff))
+
+
+# ------------------------------------------------------------------------------
+
+
+def load_wav(f: BinaryIO):
+ samples = list()
+
+ f_expect(f, b'RIFF')
+ file_len = f_chomp_u32_le(f)
+ f_expect(f, b'WAVE')
+
+ f_expect(f, b'fmt ')
+ fmt_len = f_chomp_u32_le(f)
+ audio_format = f_chomp_u16_le(f)
+ num_chans = f_chomp_u16_le(f)
+ rate = f_chomp_u32_le(f)
+ bytes_per_sec = f_chomp_u32_le(f)
+ bytes_per_block = f_chomp_u16_le(f)
+ bits_per_sample = f_chomp_u16_le(f)
+
+ f_skipto(f, b'data') # Some WAV files have more sections, so skip over those
+ data_len = f_chomp_u32_le(f)
+
+ assert fmt_len == 16
+ assert audio_format == 1
+ assert num_chans == 2
+ assert rate == 44100
+ assert bits_per_sample == 16
+ assert bytes_per_block == bits_per_sample * num_chans / 8
+ assert bytes_per_sec == bytes_per_block * rate
+
+ for i in range(int(data_len / bytes_per_block)):
+ samp_l = f_chomp_s16_le(f)
+ samp_r = f_chomp_s16_le(f)
+ samp = (samp_l + samp_r) / 2
+ samples.append(samp)
+
+ return samples
+
+
+def compress_chunk(c: List[fft.C], size: int, scale: float = 200.0):
+ n = len(c)
+ n2 = int(n/2)
+ x0 = fft.fft_iter(c)
+ x1 = [int(x.magnitude()/scale) for x in x0[0:n2+1]]
+ x2 = [(i, p) for i, p in enumerate(x1)]
+ x2.sort(key=lambda x: x[1], reverse=True)
+ x3 = x2[:20] # How bad will it sound with only 20 bins? Let's find out!
+ return x3
+
+
+def do_jankify(f: BinaryIO, g: BinaryIO):
+ print('Loading...')
+ samples = load_wav(f)
+ print('Jankifying...')
+ f_write_u32_le(g, int(len(samples)/1024))
+ for i in range(0, len(samples), 1024):
+ print(i, len(samples)) # Obnoxious, but less obnoxious than not knowing
+ block = [fft.C(s,0) for s in samples[i:i+1024]]
+ if len(block) < 1024:
+ block += [0.0]*(1024-len(block))
+ x = compress_chunk(block, 0)
+ for i, p in x:
+ f_write_u16_le(g, i)
+ f_write_u16_le(g, p)
+
+
+def do_unjank(f: BinaryIO, g: BinaryIO):
+ scale = 200
+ samples = list()
+ try:
+ num_blocks = f_chomp_u32_le(f)
+ for i in range(num_blocks):
+ print(i, num_blocks) # Obnoxious, but less obnoxious than not knowing
+ block = [fft.C(0,0)]*1024
+ for i in range(20):
+ i = f_chomp_u16_le(f)
+ p = f_chomp_u16_le(f)
+ block[i] = fft.C(p*scale,0)
+ c0 = fft.ifft_iter(block)
+ c1 = [int(c.r) for c in c0]
+ samples.extend(c1)
+ except Exception: # This is fine. Listen, don't worry about it, okay?
+ pass
+
+ len_data = len(samples) * 2
+ len_file = len_data + 44
+
+ g.write(b'RIFF')
+ f_write_u32_le(g, len_file)
+ g.write(b'WAVE')
+
+ g.write(b'fmt ')
+ f_write_u32_le(g, 16)
+ f_write_u16_le(g, 1)
+ f_write_u16_le(g, 1)
+ f_write_u32_le(g, 44100)
+ f_write_u32_le(g, 44100*2)
+ f_write_u16_le(g, 2)
+ f_write_u16_le(g, 16)
+
+ g.write(b'data')
+ f_write_u32_le(g, len_data)
+ for sample in samples:
+ f_write_s16_le(g, sample)
+
+
+# ------------------------------------------------------------------------------
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(description='Jankman pseudo-mp3 encoder/decoder')
+ subparsers = parser.add_subparsers(help='Operation', required=True, dest='cmd')
+ jankify = subparsers.add_parser('jankify', help='Convert WAV file to pseudo-mp3')
+ unjank = subparsers.add_parser('unjank', help='Convert pseudo-mp3 file to WAV')
+ jankify.add_argument('--input_file', '-i', required=True, help='Input filename')
+ jankify.add_argument('--output_file', '-o', required=True, help='Output filename')
+ unjank.add_argument('--input_file', '-i', required=True, help='Input filename')
+ unjank.add_argument('--output_file', '-o', required=True, help='Output filename')
+
+ args = parser.parse_args()
+ if args.cmd == 'jankify':
+ with open(args.input_file, 'rb') as f:
+ with open(args.output_file, 'wb') as g:
+ do_jankify(f, g)
+ elif args.cmd == 'unjank':
+ with open(args.input_file, 'rb') as f:
+ with open(args.output_file, 'wb') as g:
+ do_unjank(f, g)
+ else:
+ parser.print_usage()
+ return 1
+
+ return 0
+
+
+if __name__ == '__main__':
+ exit(main())