module music_streamer ( input clk, input rst, input tempo_up, input tempo_down, input play_pause, input reverse, output [2:0] leds, output [23:0] tone ); wire [9:0] last_address; wire reset, valid_change; reg [23:0] delay; reg [9:0] address; reg [23:0] clk_counter; reg [1:0] next_state, curr_state; // Tempo control localparam [23:0] DELTA_TEMPO = 500_000; // localparam [23:0] BASE_DELAY = 5_000_000; // 1/25 sec/tone localparam [23:0] MAX_DELAY = ~0 - DELTA_TEMPO; // prevent overflow // FSM states localparam [1:0] REGULAR_PLAY = 2'd0, REVERSE_PLAY = 2'd1, PAUSED = 2'd2, S3 = 2'd3; // unused wire [23:0] rom_out; assign tone = (curr_state == PAUSED) ? 24'd0 : rom_out; rom memory (.address(address), .data(rom_out), .last_address(last_address) ); // Ensures changing tempo doesn't cause problems assign valid_change = (delay > DELTA_TEMPO) && (delay < MAX_DELAY); // Control notes being played always @(posedge clk) begin if (rst) begin address <= 0; clk_counter <= 0; end else if (curr_state == PAUSED) begin address <= address; clk_counter <= clk_counter; end else if (clk_counter == delay && curr_state == REGULAR_PLAY) begin address <= (address + 1) % (last_address + 1); clk_counter <= 0; end else if (clk_counter == delay && curr_state == REVERSE_PLAY) begin address <= (address - 1) % (last_address + 1); clk_counter <= 0; end else clk_counter <= clk_counter + 1; end // Control tempo always @(posedge clk) begin if (rst) delay <= BASE_DELAY; else if (tempo_up && valid_change) delay <= delay - DELTA_TEMPO; else if (tempo_down && valid_change) delay <= delay + DELTA_TEMPO; end // ---------------------------------------------------- // FSM Control Logic // ---------------------------------------------------- assign leds[0] = (curr_state == REGULAR_PLAY); assign leds[1] = (curr_state == PAUSED); assign leds[2] = (curr_state == REVERSE_PLAY); // FSM state transition logic always @(*) begin next_state = curr_state; case (curr_state) REGULAR_PLAY : begin if (play_pause) next_state = PAUSED; else if (reverse) next_state = REVERSE_PLAY; end PAUSED : if (play_pause) next_state = REGULAR_PLAY; REVERSE_PLAY : begin if (play_pause) next_state = PAUSED; else if (reverse) next_state = REGULAR_PLAY; end S3 : next_state = REGULAR_PLAY; endcase end // FSM transition always @(posedge clk) begin if (rst) curr_state <= REGULAR_PLAY; // initial else curr_state <= next_state; end endmodule