module stud_ds_volume
#(
	parameter AUDIO_WIDTH=16,					// audio data input and output width
	VOLUME_WIDTH=8								// volume input width
)
(
	output reg [AUDIO_WIDTH - 1:0] audio_o,		// audio data output (unsigned)

	input signed [AUDIO_WIDTH - 1:0] audio_i,	// audio data input (signed)

	input mute_i,								// mute input, 1'b0 => normal operation, 1'b1 => output muted
	input [VOLUME_WIDTH - 1:0] volume_i,		// volume input (unsigned)

	input clk_i,								// clock input
	input n_rst_i								// active low synchronous reset
);

// actual volume, an offset of 1 is added to the volume input so that the audio data remains unchanged at
// maximum volume
reg [VOLUME_WIDTH : 0] volume;
// scaled signed audio data
reg signed [AUDIO_WIDTH : 0] audio_scaled;
// scaled audio data offset to unsigned value range, but still in signed format
reg signed [AUDIO_WIDTH-1 : 0] audio_offset;
// scaled, unsigned audio data
reg [AUDIO_WIDTH-1 : 0] next_audio_out;
/* verilator lint_off UNUSED */
reg dummy1;
reg [VOLUME_WIDTH-1:0] dummy2;
/* verilator lint_on UNUSED */

// combinatorics
always @* begin
	if (mute_i) begin
		// mute input activated, set volume to 0
		volume = {VOLUME_WIDTH + 1 {1'b0}};
	end else begin
		// normal operation, add 1 to volume input
		volume = {1'b0, volume_i} + {{VOLUME_WIDTH {1'b0}}, 1'b1};
	end

	// multiply input data by volume and shift right by VOLUME_WIDTH
	{dummy2,audio_scaled} = ({{VOLUME_WIDTH {audio_i[AUDIO_WIDTH - 1]}}, audio_i} * volume) >>> VOLUME_WIDTH;

	// add 2 ^ (AUDIO_WIDTH - 1) to convert the signed audio data to the unsigned data range
	{dummy1,audio_offset} = audio_scaled[AUDIO_WIDTH : 0] + {2'b01, {AUDIO_WIDTH - 1 {1'b0}}};
	
	// truncate result to AUDIO_WIDTH bits
	next_audio_out = audio_offset[AUDIO_WIDTH - 1 : 0];
end

// registers
always @(posedge clk_i) begin
	if (!n_rst_i) begin
		// synchronously reset register values
		// start audio output at 50 % i.e. 0
		audio_o <= {1'b0, {AUDIO_WIDTH - 1 {1'b1}}};
	end else begin
		audio_o <= next_audio_out;
	end
end
	
endmodule