1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity pixeldata is
generic(
NOTE_HEAD_OFFSET : integer := 300; -- y coordinate of center of note head
NOTE_WIDTH : integer := 110; -- note image width
NOTE_HEIGHT : integer := 345; -- note image height
STAFF_SPACING : integer := 50; -- pitch between staff lines
STAFF_TOP_Y : integer := 220); -- y position of first staff line
port(
CLK: in std_logic; -- system clock
RESET: in std_logic; -- async reset
X, Y: in std_logic_vector(9 downto 0); -- pixel x/y
NOTE_IDX: in std_logic_vector(3 downto 0);
NOTE_WRONG: in std_logic;
RGB: out std_logic_vector(11 downto 0)); -- RGB output color
end pixeldata;
architecture Behavioral of pixeldata is
component half_note_rom is port (
clka : in std_logic;
addra : in std_logic_vector(15 downto 0);
douta : out std_logic_vector(0 downto 0));
end component;
signal iX, iY: unsigned (9 downto 0); -- pixel x/y
signal address : unsigned (15 downto 0);
signal data : std_logic_vector (0 downto 0);
signal NOTE_INDEX : integer;
begin
iX <= unsigned(X);
iY <= unsigned(Y);
NOTE_INDEX <= to_integer(unsigned(NOTE_IDX));
rom: component half_note_rom port map (
clka => CLK,
addra => std_logic_vector (address),
douta => data
);
process (CLK)
variable note_x : integer;
variable note_y : integer;
variable note_upright : std_logic;
variable pixel_index : integer;
begin
if RESET = '1' then
RGB <= (others => '0');
address <= (others => '0');
note_x := 0;
note_y := 0;
note_upright := '1';
elsif rising_edge(CLK) then
-- calculate which notes are displayed upright
case NOTE_IDX is
-- f,g,a upright note
when "0000" | "0001" | "0010" => note_upright := '1';
-- b,c,d,e,f hanging note
when others => note_upright := '0';
end case;
-- base note x position
note_x := 100;
-- base note y position (bottom staff y position, f)
note_y := STAFF_TOP_Y + 4 * STAFF_SPACING;
-- shift note y up by half a staff space for each increment of note_index
note_y := note_y - NOTE_INDEX * (STAFF_SPACING / 2);
-- shift up note depending on if displayed upside down or not
case note_upright is
when '0' => note_y := note_y - NOTE_HEIGHT + NOTE_HEAD_OFFSET;
when '1' => note_y := note_y - NOTE_HEAD_OFFSET;
end case;
pixel_index := to_integer(iX) - note_x + (to_integer(iY) - note_y) * NOTE_WIDTH;
if note_upright = '0' then
-- invert coordinates
pixel_index := NOTE_WIDTH * NOTE_HEIGHT - pixel_index;
end if;
address <= to_unsigned(pixel_index, address'length);
-- white background by default
RGB <= x"fff";
-- black staff lines
if Y = STAFF_TOP_Y + 0 * STAFF_SPACING then RGB <= x"000"; end if;
if Y = STAFF_TOP_Y + 1 * STAFF_SPACING then RGB <= x"000"; end if;
if Y = STAFF_TOP_Y + 2 * STAFF_SPACING then RGB <= x"000"; end if;
if Y = STAFF_TOP_Y + 3 * STAFF_SPACING then RGB <= x"000"; end if;
if Y = STAFF_TOP_Y + 4 * STAFF_SPACING then RGB <= x"000"; end if;
-- display note if in correct opsition
if (iX >= note_x) and (iX < (note_x + NOTE_WIDTH)) and
(iY >= note_y) and (iY < (note_y + NOTE_HEIGHT)) then
if data(0) = '0' then
RGB <= x"f00" when NOTE_WRONG = '1' else x"000";
end if;
end if;
end if;
end process;
end Behavioral;
|