Lab 3: Audio Processing System #3
@@ -3,7 +3,7 @@ USE IEEE.STD_LOGIC_1164.ALL;
|
|||||||
USE IEEE.NUMERIC_STD.ALL;
|
USE IEEE.NUMERIC_STD.ALL;
|
||||||
|
|
||||||
-- Entity: LFO (Low Frequency Oscillator) - Alternative Implementation
|
-- Entity: LFO (Low Frequency Oscillator) - Alternative Implementation
|
||||||
-- Purpose: Applies tremolo effect to audio by modulating amplitude with a triangular wave
|
-- Purpose: Applies effect to audio by modulating amplitude with a triangular wave
|
||||||
-- This is a simplified, single-process implementation compared to the pipelined version
|
-- This is a simplified, single-process implementation compared to the pipelined version
|
||||||
-- Provides real-time audio amplitude modulation for musical effects
|
-- Provides real-time audio amplitude modulation for musical effects
|
||||||
ENTITY LFO IS
|
ENTITY LFO IS
|
||||||
@@ -106,7 +106,7 @@ BEGIN
|
|||||||
step_counter <= 0; -- Reset counter for next period
|
step_counter <= 0; -- Reset counter for next period
|
||||||
|
|
||||||
-- Check for triangular wave direction changes at extremes
|
-- Check for triangular wave direction changes at extremes
|
||||||
-- Note: Using (2^n - 2) and 1 instead of (2^n - 1) and 0 to avoid edge cases
|
-- Note: Using (2^n - 2) and 1 instead of (2^n - 1) and 0 due to process signal assignment
|
||||||
IF tri_counter = (2 ** TRIANGULAR_COUNTER_LENGHT) - 2 THEN
|
IF tri_counter = (2 ** TRIANGULAR_COUNTER_LENGHT) - 2 THEN
|
||||||
direction_up <= '0'; -- Switch to descending at near-maximum
|
direction_up <= '0'; -- Switch to descending at near-maximum
|
||||||
|
|
||||||
@@ -180,8 +180,8 @@ BEGIN
|
|||||||
-- Data input logic: Process new audio samples when available and output is ready
|
-- Data input logic: Process new audio samples when available and output is ready
|
||||||
IF s_axis_tvalid = '1' AND (m_axis_tready = '1' OR m_axis_tvalid_int = '0') THEN
|
IF s_axis_tvalid = '1' AND (m_axis_tready = '1' OR m_axis_tvalid_int = '0') THEN
|
||||||
IF lfo_enable = '1' THEN
|
IF lfo_enable = '1' THEN
|
||||||
-- Apply LFO tremolo effect: multiply audio sample by triangular wave
|
-- Apply LFO effect: multiply audio sample by triangular wave
|
||||||
-- This creates amplitude modulation (tremolo effect)
|
-- This creates amplitude modulation (effect)
|
||||||
m_axis_tdata_temp <= signed(s_axis_tdata) * tri_counter;
|
m_axis_tdata_temp <= signed(s_axis_tdata) * tri_counter;
|
||||||
s_axis_tlast_reg <= s_axis_tlast; -- Register channel indicator
|
s_axis_tlast_reg <= s_axis_tlast; -- Register channel indicator
|
||||||
|
|
||||||
@@ -212,11 +212,11 @@ BEGIN
|
|||||||
|
|
||||||
-- LFO Implementation Summary:
|
-- LFO Implementation Summary:
|
||||||
-- 1. Generates triangular wave at frequency controlled by joystick input
|
-- 1. Generates triangular wave at frequency controlled by joystick input
|
||||||
-- 2. When enabled: multiplies audio samples by triangular wave (tremolo effect)
|
-- 2. When enabled: multiplies audio samples by triangular wave (multiplier value range from 0 to 1)
|
||||||
-- 3. When disabled: passes audio through unchanged (bypass mode)
|
-- 3. When disabled: passes audio through unchanged (bypass mode)
|
||||||
-- 4. Uses proper AXI4-Stream handshaking for real-time audio processing
|
-- 4. Uses proper AXI4-Stream handshaking for real-time audio processing
|
||||||
--
|
--
|
||||||
-- Tremolo Effect Characteristics:
|
-- Effect Characteristics:
|
||||||
-- - Frequency range: Approximately 0.1Hz to 10Hz (typical for audio LFO)
|
-- - Frequency range: Approximately 0.1Hz to 10Hz (typical for audio LFO)
|
||||||
-- - Modulation depth: Controlled by TRIANGULAR_COUNTER_LENGHT generic
|
-- - Modulation depth: Controlled by TRIANGULAR_COUNTER_LENGHT generic
|
||||||
-- - Waveform: Triangular (linear amplitude changes, smooth transitions)
|
-- - Waveform: Triangular (linear amplitude changes, smooth transitions)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ USE ieee.numeric_std.ALL;
|
|||||||
|
|
||||||
-- Entity: all_pass_filter
|
-- Entity: all_pass_filter
|
||||||
-- Purpose: A pass-through filter that maintains the same interface and timing
|
-- Purpose: A pass-through filter that maintains the same interface and timing
|
||||||
-- characteristics as a moving average filter but passes data unchanged.
|
-- characteristics as the moving average filter but passes data unchanged.
|
||||||
ENTITY all_pass_filter IS
|
ENTITY all_pass_filter IS
|
||||||
GENERIC (
|
GENERIC (
|
||||||
TDATA_WIDTH : POSITIVE := 24 -- Width of the data bus in bits
|
TDATA_WIDTH : POSITIVE := 24 -- Width of the data bus in bits
|
||||||
@@ -36,9 +36,9 @@ ARCHITECTURE Behavioral OF all_pass_filter IS
|
|||||||
-- Internal slave interface signals
|
-- Internal slave interface signals
|
||||||
SIGNAL s_axis_tready_int : STD_LOGIC := '0'; -- Internal ready signal for input
|
SIGNAL s_axis_tready_int : STD_LOGIC := '0'; -- Internal ready signal for input
|
||||||
SIGNAL s_axis_tlast_reg : STD_LOGIC := '0'; -- Registered version of input tlast
|
SIGNAL s_axis_tlast_reg : STD_LOGIC := '0'; -- Registered version of input tlast
|
||||||
|
SIGNAL s_axis_tdata_reg : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); -- Temporary storage for input data
|
||||||
|
|
||||||
-- Internal data storage and master interface signals
|
-- Internal data storage and master interface signals
|
||||||
SIGNAL m_axis_tdata_temp : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); -- Temporary storage for input data
|
|
||||||
SIGNAL m_axis_tvalid_int : STD_LOGIC := '0'; -- Internal valid signal for output
|
SIGNAL m_axis_tvalid_int : STD_LOGIC := '0'; -- Internal valid signal for output
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
@@ -69,7 +69,7 @@ BEGIN
|
|||||||
trigger <= '0'; -- Clear data processing trigger
|
trigger <= '0'; -- Clear data processing trigger
|
||||||
s_axis_tlast_reg <= '0'; -- Clear registered tlast
|
s_axis_tlast_reg <= '0'; -- Clear registered tlast
|
||||||
s_axis_tready_int <= '0'; -- Not ready to accept data during reset
|
s_axis_tready_int <= '0'; -- Not ready to accept data during reset
|
||||||
m_axis_tdata_temp <= (OTHERS => '0'); -- Clear temporary data storage
|
s_axis_tdata_reg <= (OTHERS => '0'); -- Clear temporary data storage
|
||||||
m_axis_tvalid_int <= '0'; -- No valid data on output during reset
|
m_axis_tvalid_int <= '0'; -- No valid data on output during reset
|
||||||
m_axis_tlast <= '0'; -- Clear output tlast
|
m_axis_tlast <= '0'; -- Clear output tlast
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ BEGIN
|
|||||||
-- (either no valid data pending OR downstream is ready)
|
-- (either no valid data pending OR downstream is ready)
|
||||||
IF trigger = '1' AND (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN
|
IF trigger = '1' AND (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN
|
||||||
-- Transfer stored data to output
|
-- Transfer stored data to output
|
||||||
m_axis_tdata <= m_axis_tdata_temp; -- Output the stored input data unchanged
|
m_axis_tdata <= s_axis_tdata_reg; -- Output the stored input data unchanged
|
||||||
m_axis_tlast <= s_axis_tlast_reg; -- Output the registered tlast signal
|
m_axis_tlast <= s_axis_tlast_reg; -- Output the registered tlast signal
|
||||||
|
|
||||||
-- Set output control signals
|
-- Set output control signals
|
||||||
@@ -101,7 +101,7 @@ BEGIN
|
|||||||
IF s_axis_tvalid = '1' AND s_axis_tready_int = '1' THEN
|
IF s_axis_tvalid = '1' AND s_axis_tready_int = '1' THEN
|
||||||
-- Store input signals for later output
|
-- Store input signals for later output
|
||||||
s_axis_tlast_reg <= s_axis_tlast; -- Register the tlast signal
|
s_axis_tlast_reg <= s_axis_tlast; -- Register the tlast signal
|
||||||
m_axis_tdata_temp <= s_axis_tdata; -- Store input data (pass-through, no processing)
|
s_axis_tdata_reg <= s_axis_tdata; -- Store input data (pass-through, no processing)
|
||||||
|
|
||||||
-- Set trigger to indicate data is ready for output
|
-- Set trigger to indicate data is ready for output
|
||||||
trigger <= '1';
|
trigger <= '1';
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ ARCHITECTURE Behavioral OF digilent_jstk2 IS
|
|||||||
|
|
||||||
-- Calculate delay in clock cycles: (delay_period + 1_SPI_clock_period) * clock_frequency
|
-- Calculate delay in clock cycles: (delay_period + 1_SPI_clock_period) * clock_frequency
|
||||||
-- This ensures proper timing between SPI packets as required by JSTK2 datasheet
|
-- This ensures proper timing between SPI packets as required by JSTK2 datasheet
|
||||||
CONSTANT DELAY_CLK_CYCLES : INTEGER := (DELAY_US + 1_000_000 / SPI_SCLKFREQ) * (CLKFREQ / 1_000_000);
|
CONSTANT DELAY_CLK_CYCLES : INTEGER := (DELAY_US + 1_000_000 / SPI_SCLKFREQ) * (CLKFREQ / 1_000_000) - 1;
|
||||||
|
|
||||||
-- State machine type definitions
|
-- State machine type definitions
|
||||||
TYPE tx_state_type IS (DELAY, SEND_CMD, SEND_RED, SEND_GREEN, SEND_BLUE, SEND_DUMMY);
|
TYPE tx_state_type IS (DELAY, SEND_CMD, SEND_RED, SEND_GREEN, SEND_BLUE, SEND_DUMMY);
|
||||||
@@ -56,7 +56,7 @@ ARCHITECTURE Behavioral OF digilent_jstk2 IS
|
|||||||
|
|
||||||
-- Timing and data storage signals
|
-- Timing and data storage signals
|
||||||
SIGNAL tx_delay_counter : INTEGER RANGE 0 TO DELAY_CLK_CYCLES := 0; -- Counter for inter-packet delay timing
|
SIGNAL tx_delay_counter : INTEGER RANGE 0 TO DELAY_CLK_CYCLES := 0; -- Counter for inter-packet delay timing
|
||||||
SIGNAL rx_cache : STD_LOGIC_VECTOR(7 DOWNTO 0); -- Temporary storage for multi-byte data reception
|
SIGNAL rx_cache : STD_LOGIC_VECTOR(s_axis_tdata'range); -- Temporary storage for multi-byte data reception
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
@@ -80,7 +80,8 @@ BEGIN
|
|||||||
"01101001" WHEN SEND_DUMMY; -- Dummy byte to complete 5-byte transaction
|
"01101001" WHEN SEND_DUMMY; -- Dummy byte to complete 5-byte transaction
|
||||||
|
|
||||||
-- TX State Machine: Sends LED color commands to JSTK2 module
|
-- TX State Machine: Sends LED color commands to JSTK2 module
|
||||||
-- Protocol: Command(1) + Red(1) + Green(1) + Blue(1) + Dummy(1) = 5 bytes total
|
-- Protocol: Command(1) + Red(1) + Green(1) + Blue(1) + Dummy(1) = 5 bytes total > Delay before next command
|
||||||
|
-- The delay is required by the JSTK datasheet to ensure proper timing between SPI transactions
|
||||||
TX : PROCESS (aclk)
|
TX : PROCESS (aclk)
|
||||||
BEGIN
|
BEGIN
|
||||||
IF rising_edge(aclk) THEN
|
IF rising_edge(aclk) THEN
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ END effect_selector;
|
|||||||
|
|
||||||
ARCHITECTURE Behavioral OF effect_selector IS
|
ARCHITECTURE Behavioral OF effect_selector IS
|
||||||
|
|
||||||
constant JOYSTICK_DEFAULT : STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0) := STD_LOGIC_VECTOR(to_unsigned(2 ** (JOYSTICK_LENGHT - 1), JOYSTICK_LENGHT)); -- Default joystick value
|
constant JOYSTICK_DEFAULT : STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0) := STD_LOGIC_VECTOR(to_unsigned(2 ** (JOYSTICK_LENGHT - 1), JOYSTICK_LENGHT)); -- Default joystick value (center position for 10-bit joystick is 512)
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
@@ -52,9 +52,11 @@ BEGIN
|
|||||||
-- X-axis behavior differs between modes
|
-- X-axis behavior differs between modes
|
||||||
-- Note: When switching between modes, some outputs are reset while others preserved
|
-- Note: When switching between modes, some outputs are reset while others preserved
|
||||||
IF effect = '1' THEN
|
IF effect = '1' THEN
|
||||||
-- LFO Mode: Y-axis controls Low Frequency Oscillator period
|
-- LFO Mode:
|
||||||
-- Used for tremolo, vibrato, or other modulation effects
|
-- Y-axis controls Low Frequency Oscillator period
|
||||||
|
-- X-axis is ignored in this mode
|
||||||
lfo_period <= jstck_y;
|
lfo_period <= jstck_y;
|
||||||
|
|
||||||
-- Volume remains at last set value (preserved from previous mode)
|
-- Volume remains at last set value (preserved from previous mode)
|
||||||
|
|
||||||
-- Reset balance to center/default position when in LFO mode
|
-- Reset balance to center/default position when in LFO mode
|
||||||
@@ -64,9 +66,9 @@ BEGIN
|
|||||||
-- Volume/Balance Mode:
|
-- Volume/Balance Mode:
|
||||||
-- Y-axis controls overall volume level
|
-- Y-axis controls overall volume level
|
||||||
-- X-axis controls left/right audio balance
|
-- X-axis controls left/right audio balance
|
||||||
-- Traditional audio mixer control mode
|
|
||||||
volume <= jstck_y;
|
volume <= jstck_y;
|
||||||
balance <= jstck_x;
|
balance <= jstck_x;
|
||||||
|
|
||||||
-- LFO period remains at last set value (preserved from previous LFO mode)
|
-- LFO period remains at last set value (preserved from previous LFO mode)
|
||||||
|
|
||||||
END IF;
|
END IF;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
LIBRARY IEEE;
|
LIBRARY IEEE;
|
||||||
USE IEEE.STD_LOGIC_1164.ALL;
|
USE IEEE.STD_LOGIC_1164.ALL;
|
||||||
USE IEEE.NUMERIC_STD.ALL;
|
USE IEEE.NUMERIC_STD.ALL;
|
||||||
|
USE IEEE.MATH_REAL.ALL;
|
||||||
|
|
||||||
-- Entity: led_level_controller
|
-- Entity: led_level_controller
|
||||||
-- Purpose: Audio level meter using LEDs to display real-time audio amplitude
|
-- Purpose: Audio level meter using LEDs to display real-time audio amplitude
|
||||||
@@ -34,7 +35,10 @@ ARCHITECTURE Behavioral OF led_level_controller IS
|
|||||||
-- Calculate clock cycles needed for LED refresh timing
|
-- Calculate clock cycles needed for LED refresh timing
|
||||||
-- Formula: (refresh_time_ms * 1_000_000 ns/ms) / clock_period_ns
|
-- Formula: (refresh_time_ms * 1_000_000 ns/ms) / clock_period_ns
|
||||||
-- Example: (1ms * 1,000,000) / 10ns = 100,000 cycles for 1ms refresh at 100MHz
|
-- Example: (1ms * 1,000,000) / 10ns = 100,000 cycles for 1ms refresh at 100MHz
|
||||||
CONSTANT REFRESH_CYCLES : INTEGER := (refresh_time_ms * 1_000_000) / clock_period_ns;
|
CONSTANT REFRESH_CYCLES : INTEGER := (refresh_time_ms * 1_000_000) / clock_period_ns - 1;
|
||||||
|
|
||||||
|
-- Calculate the number of bits needed to represent the number of LEDs
|
||||||
|
CONSTANT NUMLEDS_BITS : INTEGER := INTEGER(ceil(log2(real(NUM_LEDS))));
|
||||||
|
|
||||||
-- LED refresh timing control signals
|
-- LED refresh timing control signals
|
||||||
SIGNAL refresh_counter : INTEGER RANGE 0 TO REFRESH_CYCLES := 0; -- Counts clock cycles between LED updates
|
SIGNAL refresh_counter : INTEGER RANGE 0 TO REFRESH_CYCLES := 0; -- Counts clock cycles between LED updates
|
||||||
@@ -91,7 +95,7 @@ BEGIN
|
|||||||
refresh_tick <= '0';
|
refresh_tick <= '0';
|
||||||
ELSE
|
ELSE
|
||||||
-- Normal operation: Count clock cycles and generate refresh tick
|
-- Normal operation: Count clock cycles and generate refresh tick
|
||||||
IF refresh_counter = REFRESH_CYCLES - 1 THEN
|
IF refresh_counter = REFRESH_CYCLES THEN
|
||||||
-- End of refresh period: Reset counter and generate tick pulse
|
-- End of refresh period: Reset counter and generate tick pulse
|
||||||
refresh_counter <= 0;
|
refresh_counter <= 0;
|
||||||
refresh_tick <= '1'; -- Single clock cycle pulse for LED update
|
refresh_tick <= '1'; -- Single clock cycle pulse for LED update
|
||||||
@@ -109,7 +113,7 @@ BEGIN
|
|||||||
-- Updates only when refresh_tick is active to maintain stable visual display
|
-- Updates only when refresh_tick is active to maintain stable visual display
|
||||||
PROCESS (aclk)
|
PROCESS (aclk)
|
||||||
VARIABLE combined_amp : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0); -- Combined amplitude of both channels
|
VARIABLE combined_amp : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0); -- Combined amplitude of both channels
|
||||||
VARIABLE led_level : INTEGER RANGE 0 TO NUM_LEDS := 0; -- Calculated LED level for bar graph display
|
VARIABLE led_level : INTEGER RANGE 0 TO 2**NUMLEDS_BITS := 0; -- Calculated LED level for bar graph display
|
||||||
BEGIN
|
BEGIN
|
||||||
IF rising_edge(aclk) THEN
|
IF rising_edge(aclk) THEN
|
||||||
IF aresetn = '0' THEN
|
IF aresetn = '0' THEN
|
||||||
@@ -123,6 +127,8 @@ BEGIN
|
|||||||
-- Combine left and right channel amplitudes
|
-- Combine left and right channel amplitudes
|
||||||
-- The sum of the absolute values of both channels gives a measure of total audio energy.
|
-- The sum of the absolute values of both channels gives a measure of total audio energy.
|
||||||
-- RESIZE ensures the sum fits within the variable's bit width.
|
-- RESIZE ensures the sum fits within the variable's bit width.
|
||||||
|
-- There isn't data loss here since both abs_l and abs_r are one bit shorter than combined_amp,
|
||||||
|
-- due to the absolute value operation.
|
||||||
combined_amp := RESIZE(abs_l + abs_r, combined_amp'LENGTH);
|
combined_amp := RESIZE(abs_l + abs_r, combined_amp'LENGTH);
|
||||||
|
|
||||||
-- Normalize combined amplitude to LED scale (0 to NUM_LEDS)
|
-- Normalize combined amplitude to LED scale (0 to NUM_LEDS)
|
||||||
@@ -130,7 +136,7 @@ BEGIN
|
|||||||
-- For 24-bit audio, shifting by (CHANNEL_LENGHT - 4) reduces the range to approximately 4 bits (0-15).
|
-- For 24-bit audio, shifting by (CHANNEL_LENGHT - 4) reduces the range to approximately 4 bits (0-15).
|
||||||
-- Adding 1 ensures that at least one LED lights up for any non-zero audio input.
|
-- Adding 1 ensures that at least one LED lights up for any non-zero audio input.
|
||||||
-- Example: For 24-bit input, 1 + (combined_amp >> 20) gives a range from 1 to 16.
|
-- Example: For 24-bit input, 1 + (combined_amp >> 20) gives a range from 1 to 16.
|
||||||
led_level := 1 + to_integer(shift_right(combined_amp, CHANNEL_LENGHT - 4));
|
led_level := 1 + to_integer(shift_right(combined_amp, CHANNEL_LENGHT - NUMLEDS_BITS));
|
||||||
|
|
||||||
-- Saturation protection: Limit LED level to maximum available LEDs
|
-- Saturation protection: Limit LED level to maximum available LEDs
|
||||||
-- Prevents overflow and ensures the LED index stays within bounds.
|
-- Prevents overflow and ensures the LED index stays within bounds.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ USE IEEE.STD_LOGIC_1164.ALL;
|
|||||||
USE ieee.numeric_std.ALL;
|
USE ieee.numeric_std.ALL;
|
||||||
|
|
||||||
-- Entity: moving_average_filter
|
-- Entity: moving_average_filter
|
||||||
-- Purpose: Implements a finite impulse response (FIR) low-pass filter using moving average
|
-- Purpose: Implements a moving average filter for audio data
|
||||||
-- Maintains separate circular buffers for left and right audio channels
|
-- Maintains separate circular buffers for left and right audio channels
|
||||||
-- Filter order is configurable as 2^(FILTER_ORDER_POWER) samples
|
-- Filter order is configurable as 2^(FILTER_ORDER_POWER) samples
|
||||||
ENTITY moving_average_filter IS
|
ENTITY moving_average_filter IS
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ BEGIN
|
|||||||
|
|
||||||
-- Volume to exponent conversion process
|
-- Volume to exponent conversion process
|
||||||
-- Converts joystick y-axis position to bit-shift amount for exponential volume scaling
|
-- Converts joystick y-axis position to bit-shift amount for exponential volume scaling
|
||||||
PROCESS (aclk)
|
VOLUME_CALC : PROCESS (aclk)
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
IF rising_edge(aclk) THEN
|
IF rising_edge(aclk) THEN
|
||||||
@@ -78,6 +78,7 @@ BEGIN
|
|||||||
-- volume = 0-479: Negative exponent (attenuation, right shift)
|
-- volume = 0-479: Negative exponent (attenuation, right shift)
|
||||||
-- volume = 480-543: Zero exponent (unity gain, dead zone)
|
-- volume = 480-543: Zero exponent (unity gain, dead zone)
|
||||||
-- volume = 544-1023: Positive exponent (amplification, left shift)
|
-- volume = 544-1023: Positive exponent (amplification, left shift)
|
||||||
|
|
||||||
volume_exp_mult <= to_integer(
|
volume_exp_mult <= to_integer(
|
||||||
shift_right(
|
shift_right(
|
||||||
signed('0' & volume) - to_signed(VOL_MID - DEAD_ZONE, volume'length + 1),
|
signed('0' & volume) - to_signed(VOL_MID - DEAD_ZONE, volume'length + 1),
|
||||||
@@ -89,11 +90,11 @@ BEGIN
|
|||||||
|
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
END PROCESS;
|
END PROCESS VOLUME_CALC;
|
||||||
|
|
||||||
-- AXI4-Stream data processing
|
-- AXI4-Stream data processing
|
||||||
-- Applies exponential volume scaling using bit-shifting multiplication
|
-- Applies exponential volume scaling using bit-shifting multiplication
|
||||||
PROCESS (aclk)
|
AXIS : PROCESS (aclk)
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
IF rising_edge(aclk) THEN
|
IF rising_edge(aclk) THEN
|
||||||
@@ -155,7 +156,7 @@ BEGIN
|
|||||||
|
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
END PROCESS;
|
END PROCESS AXIS;
|
||||||
|
|
||||||
-- Example scaling factors (VOLUME_STEP_2 = 6, 64 values per step):
|
-- Example scaling factors (VOLUME_STEP_2 = 6, 64 values per step):
|
||||||
-- volume_exp_mult = -3: Divide by 8 (>>3)
|
-- volume_exp_mult = -3: Divide by 8 (>>3)
|
||||||
|
|||||||
@@ -82,12 +82,10 @@ BEGIN
|
|||||||
|
|
||||||
IF signed(s_axis_tdata) > signed(HIGHER_BOUND_VEC) THEN
|
IF signed(s_axis_tdata) > signed(HIGHER_BOUND_VEC) THEN
|
||||||
-- Positive overflow: Clip to maximum positive value
|
-- Positive overflow: Clip to maximum positive value
|
||||||
-- This prevents "wraparound" distortion from mathematical overflow
|
|
||||||
m_axis_tdata <= HIGHER_BOUND_VEC;
|
m_axis_tdata <= HIGHER_BOUND_VEC;
|
||||||
|
|
||||||
ELSIF signed(s_axis_tdata) < signed(LOWER_BOUND_VEC) THEN
|
ELSIF signed(s_axis_tdata) < signed(LOWER_BOUND_VEC) THEN
|
||||||
-- Negative overflow: Clip to maximum negative value
|
-- Negative overflow: Clip to maximum negative value
|
||||||
-- This prevents "wraparound" distortion from mathematical underflow
|
|
||||||
m_axis_tdata <= LOWER_BOUND_VEC;
|
m_axis_tdata <= LOWER_BOUND_VEC;
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
@@ -109,11 +107,4 @@ BEGIN
|
|||||||
|
|
||||||
END PROCESS;
|
END PROCESS;
|
||||||
|
|
||||||
-- Saturation Purpose and Benefits:
|
|
||||||
-- 1. Prevents audio distortion from mathematical overflow
|
|
||||||
-- 2. Maintains audio dynamic range within valid bit representation
|
|
||||||
-- 3. Reduces wide multiplication results back to standard audio format
|
|
||||||
-- 4. Provides "soft limiting" behavior for volume control
|
|
||||||
-- 5. Ensures compatibility with downstream audio processing blocks
|
|
||||||
|
|
||||||
END Behavioral;
|
END Behavioral;
|
||||||
Reference in New Issue
Block a user