Issues
You have two errors. The first, pointed out by Brian, your range is wrong. An easy way to express the range is to use 'range. This is shown in the code below.
In addition, you want to change the class of your byte_in parameter to constant, also shown in the code below.
Solution
procedure send_midi_byte (
constant byte_in : in std_logic_vector;
signal midi_out : out std_logic
) is
begin
midi_out <= '0';
wait for baudrate;
for i in byte_in'range loop
midi_out <= byte_in(i);
wait for baudrate;
end loop;
midi_out <= '1';
wait for baudrate;
end send_midi_byte;
So why constant? Constant means that the parameter is static for the lifetime of the subprogram call. Constant parameters allow anything that produces a value (literal, expression, or even signal or variable name), such as:
send_midi_byte(x"90", midi_in_int);
for i in 0 to 10 loop
send_midi_byte(x"90" + i, midi_in_int);
end loop;
You are already familiar with this as all of the language operators (implemented as functions) have constant classed parameters (it is the default and in the standard packages it is common to leave it off).
Guidelines for Parameters
For inputs:
Use a signal when an update is expected on the object - such as using 'event, or using the object in a wait statement. Generally this means the object is coming from the architecture (such as the DUT).
Use a constant when you need to pass a literal value.
For outputs:
Use a signal when passing a value to the architecture (such as the DUT).
Use a variable when passing a value back to the local process.
Why should the parameter be a constant
In your example, it will work with a signal, however, the use model will always be, 1) assign to the signal, and then 2) call the subprogram:
byte_slv <= x"90";
send_midi_byte(byte_slv, midi_in_int);
This may or may not annoy you enough to be a problem. For other procedures, the update of the signal parameter may indeed end up being a delta cycle too late. This too can be worked around in the subprogram easily enough.
OTOH, as soon as you want to call your send_midi_byte procedure from another procedure, it gets more difficult or it does not work at all. In the procedure below, we try testing by sending incrementing bytes to the midi:
procedure send_inc_midi_bytes (
constant first_byte_in : in std_logic_vector;
constant number_bytes : in integer ;
signal midi_out : std_logic
) is
-- signal byte_in : std_logic_vector(7 downto 0); -- want to do this
begin
for i in 0 to number_bytes - 1 loop
byte_in <= byte_in + i ;
send_midi_byte(byte_in, midi_out);
end loop ;
end procedure send_inc_midi_bytes ;
I realize that fixing the range fixes your exact problem, but some day, you may wish to do more - at that point, you will be wishing that someone suggested that you used a constant instead of a signal.