Audio
Visualization
Final
Project – ECE 5760
Michael
Lyons – mpl56
Darbin
Reyes – der34
Introduction
The goal of our project was to input
a signal in the DE2 board, whether it be music, conversation, or noise, and be
able to analyze the signal to display visuals on the VGA output in real time. The
main focus and testing for this project was done on music being played through
a computer. The setup used for the project was a DE2 board, the on board audio codec,
and VGA display driver with an external monitor. The setup would have the user
input their music on the board line in and then the logic of our project would
output visuals on the VGA port according to the signal coming in. Once the
signal was input into the line in signal differentiation was needed and done by
amplitude, frequency, and period. Using these different measures for the
incoming signal the user selected from various visualization schemes to
display. The amplitude of the incoming signal over time was converted to a
logical mapping for the VGA and allowed for different size objects on the VGA
display. Frequency and period being very closely related were dealt with in
different ways. For frequency we used five filters in order to separate the
incoming signal into three bands. The bands corresponded to bass, cymbal, and
vocals and depending on amplitude and content in each band the display showed
different patterns and colors accordingly. The final measurement, period, was
used in a different way for the variation of the pixel colors on the VGA
display. Depending how long the period was the color schemes would change
according to that pace. The variation of pixel color was also done at faster
paces, so if the beat detected occupied quarter notes pace the colors could
change with a quarter note, half note, whole note, and two half notes. The
exact timing of each note is not necessarily accurate; however, relative pacing
or beats per minute (bpm) of the music was the goal. The reason this project
was chosen was because audio visualizes are common to find but do not
necessarily correspond to the music being played. The goal of this project was
to create visuals that actually followed the music for a better listening
experience.
High Level Design
The critical path of this project
was to take an input signal from the audio codec and then send this signal
through various calculation and visualization modules to produce an output on
the VGA display. The block flow diagram of the high level design can be seen
below in Figure 1.A second more precise visualization unit was also created and
is explained in the hardware section and used for obtaining accurate and simple
results. The first unit that the audio input signal was sent to the period
calculation unit in the top module. The period calculation unit repeatedly
finds the period on the expiration of a timer and stored the largest period
found in a register. The period calculation was done through the method of zero
crossing. Before detecting zero crossing the audio signal had to be low passed
and down sampled so that only low frequencies could be used to figure out the
period. Using the low frequencies is beneficial because it gives a good
estimate of the beat of the song. With the beat of the song one can change
images and colors in a period manner with the music being played. In order to
accomplish finding the period to estimate beats per minute a CIC filter was
used to low pass and down sample to the audio clock. From there the signal was
down sampled even more using a thousand hertz. According to the Shannon’s
sampling theorem this would only allow frequencies of up to 500 Hz to be
detected. A frequency from 500 Hz and down is the bass range of the music where
the beats can usually be found. After the filtering and down sampling are
completed three zero crossings are found so that an entire period is traversed
and the resulting number of clock cycles is used to judge beats per minute
which is then used to change the image as well as the color on the screen.
The
audio signal is also sent into three low pass chebychev filters each with a
different cutoff frequency for their respective ranges of: bass, cymbal, and
voice. The filters used were all infinite impulse response filters. The cymbal
filter used a four pole eighteen bit infinite impulse response filter which was
for the highest frequency range. The bass and voice filters both used a four
pole twenty seven bit infinite impulse response filter because the cutoffs
needed to be very exact considering the ranges were tight on the lower end. Details
about the filters can be found in the hardware description section below. The
cymbal and voice filters required two filters to create a pass band while the
bass filter was a single low pass filter
At
the same time the audio input enters the three filters the signal also goes
into an absolute value unit and then a height mapping unit. The absolute value
unit takes the absolute value of the incoming signal and then sends it to the
mapping unit where the height is converted to a height mapping of the VGA
screen. The absolute value unit takes
the absolute value of the current input signal by checking the first bit and
makes sure that it is zero. Once the signal has been made positive it goes into
the height mapping module which looks for the highest order one and once found the
unit outputs height that corresponds to a pixel quantity for the y axis on the
VGA display. The resulting height allows visuals to be drawn with heights that
are proportional to the incoming audio signal. The three audio filters
mentioned in the paragraph above are also put through these two units to output
their corresponding heights.
Figure 1: High Level Flow Diagram
After the filtering, period
calculation, and height mapping the audio signal is then sent into three
different display modules selectable by the user. The first of these modules is the “Cellular
automaton module” which takes the period, the audio input, and the three
filtered signals. The Cellular automaton unit draws a cellular automaton on the
VGA display. A Cellular automaton is an algorithm where the next line on the
VGA screen depends on the previous line on the VGA screen. How the next line on
the screen is determined is based on the current line’s values. Beginning with
an initial value, which in the case of our implementation could be either one
block in the center or a horizontal line of random values, the next horizontal line
will be set values based on the horizontal line that came before it. How the
next horizontal line is set based on the previous line is done with a rule that
is from zero to two hundred and fifty five or eight bits. Each rule can be
represented by an eight bit number. Each bit in that eight bit sequence can be
reached with a three bit number that represents its offset within the eight
bits. For instance the fourth bit has the sequence 3’b100 associated with it. When
given a rule in eight bits the offset sequence is contained in the previous
line. When traversing a horizontal line the three bits or pixels in this case when
referring to an LCD screen, the pixel above the current one is checked as are
the pixels immediately to the left and right of the pixel right above. If any
of these pixels is encoded as drawn then that bit is set high in the three bit offset.
If the bit offset into the rule is a one then the current pixel on the screen
is to be filled in. If the bit offset into the rule is a zero then the current
pixel is to be black. In our implementation of the Cellular Automaton the rule
is dictated by the high order bits of the period and the color of the current
pixel is not black or white but based off either output from a pixel value
controller or from the various audio signals contained within the project. The
various rules calculated and colors generated produce an array that is stored
in SRAM. The VGA then reads the values out of the SRAM if the Cellular Automaton
visualization is selected by the user.
The second of the visualization module
is the “draw bars” module which takes in the period of the signal, the audio
input, the three filter outputs, and the height bit mapping of the audio input
signal, the bass filter, cymbal filter, and voice filter outputs. Once all of
these calculated values are read into this module the current section of the
screen VGA is trying to set is traversed and as it is the draw bars
visualization figures out what to draw in the current location the VGA is
looking for. In other words the VGA looks over the entire screen from the top
left down to the bottom right. The module for the VGA outputs the current
location that it is looking for and this is an input into the module. Based on
this value the module finds out its current offset across the screen and the
corresponding height bit mapping for that location on the screen and if the
height mapping includes the current location then the pixel controller unit
outputs a new pixel value to the VGA display. The draw bars visualization draws
one hundred bars across the VGA display representing past values of the audio
input signal. The current sample of the audio signal is stored in the first
height map register and as more samples are loaded in, the sample in the first
register is passed to the next bar height register. In this manner the height map
value is passed down the bar height register chain and the height is propagated
across the screen. In this manner the magnitude of various parts of the input
audio signal can be seen over one hundred redraws of the screen at one time. In
addition to the bars being drawn across the screen there are two “eyes” at the
top of the screen that change in size with respect to some of the height
registers of the bars to represent the frequency of change in the magnitude of
the current signal being displayed by the bars. The colors in which both the
bars and “eyes” are filled in with can be changed by the user. The user can
choose to have the pixel controller run through its basic algorithm to change
the pixel colors or the user may select the available audio signals to dictate
the current color change. With this unit it is very clear to tell the
magnitudes and how the waveform progresses over time but the period is a bit
abstract since it is only used in the default algorithm to change the pixel
color scheme. When this visualization and color scheme are selected by the user
the unit will produce red, green, and blue pixel values which are output by the
unit and onto the VGA display.
The third of the visualization
modules is the “box visual module” which takes in the current calculated
period, the input audio signal, and the filtered bass, cymbal, and voice signals.
The “box visual module” also takes in the coordinates being traversed by the
VGA controller and tracks the current position on the screen and divides the
screen up into four concentric rectangles instead of draws bars and eyes. The
concentric rectangles are drawn using a grid fashion and depending on the rectangle
in the grid the VGA controller is currently traversing it is filled in with
pixel values from the pixel controller. Each rectangle on the grid not only can
change its color using the pixel controller but it can change in size. The grid
is divided up to the various audio input signals. The outer most edge’s blocks
in the grid all have their widths modulated from the left and right by the audio
input signal’s, from the line in, top four bits not including the sign bit. The
inner most grid component in the center of the screen has its width and height,
of both sides, modulated by the filter voice signal’s top four bits not
including the sign bit. The second most inner rectangle has its width modulated
from both sides by the top four bits of the cymbal input signal. The height on
the other hand is not modulated in all section of this rectangle. Only in the
bottom and top row of the second most inner rectangle is the height adjusted
for the top four bits of the cymbal audio input. The second most outer
rectangle works in a similar manner as the last rectangle but the width in both
direction modulated by the top four bits of the bass input signal. Only the
bottom and top rows of this rectangle are modulated in height by the top four
bits of the bass input signal. The top four bits of the inputted signals do not
include the sign bit so that magnitude is the measure seen when changing the
grid block size.
After all the visualization modules
red, green, and blue pixel values are all set and read into the VGA controller
appropriately to the visualization scheme selected by the user. The VGA
controller then outputs the created display onto the LCD display in the lab. The
pixel color values seen on the VGA display are drawn either from audio and
filter inputs or from the pixel controller instantiated along with each
visualization module. The goal of the pixel controller is to dictate how
quickly the “pixel variater” steps through its various pixel encoding schemes. The
“pixel variater” steps through the different combinations of colors over time
based on the current scheme passed in by the pixel controller. The speed at
which the schemes change is dictated by a counter that terminates by a multiple
of the period. Finally, other than the filters and filter generated code, audio
codec, and VGA modules given to us previous in the ECE5760 lab, there are no
existing patents, copyrights, or trademarks associated with our project. There
are also no standards used in our project.
Hardware
Referring the high level design flow
and starting from the input signal we can begin to traverse the hardware used
for this project. The input signal goes into the audio codec which is then
input into the FPGA chip on the DE2 board which allows the audio signal
available for manipulation and analysis. The inputted audio signal in our
design can be directly placed on the output line depending on the selection of
switches 16 through 14. This is a three bit value that when that choose the
output to be the output of the CIC filters, the audio signal input, the cymbal
filter output, the bass filter output, the voice filter output, and the 1000 Hz
sampling of the audio input signal for the numbers zero to five respectively. If
none of these values are selected using the switches then nothing is output on
the left channel of the line out. On the right channel the same content is
placed as was placed on the left channel.
The input from the audio codec is
also used in a top module section of code known as the period calculator. The
period calculator takes the audio input signal from the left channel and
attempts to find the low frequency periodicity of the signal. The first step in
completing this task is to filter the audio signal input through a second order
CIC filter. CIC filters were used in lab two of ECE5760 and won’t be discussed
in great detail here. The purpose of the second order CIC filter is to low pass
the signal using the twenty seven megahertz clock and the audio clock. The second
order CIC filter also down samples the signal to the audio clock and then
outputs the corresponding signal on the ‘oCIC’ wire. After the low major section of the period calculator
code is entered, which is an always blocks in the top level module at the
positive edge of the fifty megahertz clock. The first task for the period
calculation is to down sample the second order CIC filter output even further. In
this loop the count, hzCount, is used to create a 1000 Hz clock by switching
the register value of clk1000 every 25000 clock cycles. This creates a 1000 Hz
clock signal which will be used to, based on the Nyquist sample rate, to remove
all frequencies above 500 Hz. With all the high frequencies removed the hardware
can now calculate the period of this low frequency signal by looking for three
zero crossings in a row. Three zero crossings in a row traverses one period
because in one period a sinusoid will cross the time axis three times. The
crossing of the time axis can occur in the sequence of below, above, below or
above, below, above and the period is the number of cycles between the going
below samples or the going above sample respectively.
Before
looking into the state machine it is worth noting that when the system is reset
the maxPerLength, prevSample, and newMax are all set to zero and state1000 is
set to firstSample. The maxPerLength is
the maximum period length recently measured. The prevSample is the previous
sample that was in the register sample1000 and newMax is a counter that
dictates when a new value should be placed in maxPerLength. Other registers
used are periodCount, periodLength, state1000, and modIn which are the period
cycle count, current period length measured, the current state of the period
calculator, and the down sampled audio signal from 50 MHz to 27 MHz. After the
reset is no longer being pressed the state machine samples the sinusoid when
the 1000 Hz clock is high and then goes to second state of fristCross which
checks to see if between the pervious sample and the current sample if there
was a change in sign. When there is a change in sign it shows that there is a
crossing of the time axis because the magnitude goes from positive to negative.
If there is no change then the current sample is stored in previous sample and
the firstSample state is returned to. If a zero crossing is detected in either
direction the periodCount is reset to zero. The periodCount is a 32 bit
register which is used to measure how many clock cycles the period is. The
current sample (sample1000) is stored in the prevSample register and the
state1000 progresses to secondSample. In secondSample a similar action as in
firstSample is taken where if the clk1000 signal is high then a new sample from
the second order CIC filter is obtained and the secondCross state is entered. The
secondCross also attempts to see if there is a zero crossing and returns to the
secondSample state if there is no zero crossing. If there is a zero crossing
then sample1000 is stored in prevSample and the state1000 is changed to
thirdSample. In state thirdSample it also waits to obtain a new sample when the
clk1000 is high and otherwise simply wait until the clk1000 is high. Once the
clk1000 is high the thirdCross state is entered and if no zero crossing is
detected then it returns to the thirdSample state. If a zero crossing is
detected then the periodCount is stored in periodLength. The periodLength is
compared to maxPerLength which stores the maximum period measured in this
interval so far. Storing the maximum period allows us to obtain the lowest
frequency possible which is useful for measuring the amount of time between the
bass beats in the music. Then the newMax value is increment and checked to see
if it has reached 1000 yet. If the newMax register has reached 1000 then maxPerLength
is step to 1000 and newMax is set back to zero. The newMax count is implemented
because most audio signals are dynamic and will have a constantly changing
lowest frequency so it is useful to want to measure a new maxPerLength every so
often to allow the visualization to keep pace with the current audio signal. The
maxPerLength register is then put on the hex displays for the user to view.
Audio/Video
Synchronization
A
filtering scheme was developed to facilitate synchronization of the music to
what is being drawn on the screen. While common audio visualizations do not
stress synchronization, this scheme does. We found that for the user to easily
notice the synchronization between the music and the screen, the drawing had to
remain simple. As such, the visualization schemes for which the audio and video
are visually in synch the drawing was kept simple. On the other hand, to add
visually complex visualizations, we had to sacrifice synchronization with the
audio. With the complex scenes, the synchronization is not immediately obvious,
but the presented visualization is modulated by the audio to produce variation
on the screen. The following explains the filtering scheme developed to produce
audio visualizations for which the synch is obvious. The visualization schemes
that focused intensely on simplicity of visuals and synchronization with the
music are explained below under the simple visualization section.
Filtering
Scheme
Figure 2: Filtering Hardware
The filtering
scheme seen above was used in a separate hardware module for simple
visualization and is separate from the main part of the hardware shown in the
flow diagram in the high level design. The filtering scheme has five main
components:
1)
A
filter bank with 3 filters. Low pass, band-pass, High Pass.
2)
Volume
adjustment module.
3)
Absolute
value unit
4)
Thresholding
5)
Conversion
to bar height
The
filter bank contains three Chebychev, fourth order, infinite impulse response
(IIR) filters. The verilog implementation of these filters was taken from the
ECE5670 website here:
http://instruct1.cit.cornell.edu/Courses/ece576/DE2/fpgaDSP.html
The cut-off
frequencies were chosen by testing the filters in Matlab on various songs. The cheby1() function in Matlab was used to
do this. The final normalized cutoff frequencies used were:
Chebychev Low Pass: .03
Chebychev Band Pass: .02-.05
Chebychev High Pass: .5-.6
With the audio
codec running at 16bit resolution and 48KHz.
During
testing of the filter output, we observed that although the desired frequencies
were filtered, each filter unequally attenuated the input. For example, even
when the high pass filter input contained significant amounts of high frequency
sounds (e.g. cymbal beats), these frequencies were barely audible relative to
the other filter outputs. This problem
was easily solved by manually increasing the volume, however we found that it
easy to develop a method for automatically adjusting the volume. The scheme for
volume adjustment is simple. We take the average of the absolute value of the
filter output and increase the volume if it is below a certain threshold. The
amount of volume increase is proportional to how far the filter output is from
the threshold. The absolute value unit then takes the absolute value of its
input. This is a significant step toward visualizing the audio. It is easier to
modulate visuals on the screen with a signal that is proportional to the
absolute value of the audio amplitude.
Using a threshold comparison on the absolute
value of the audio signal is used to accomplish three tasks. First, it is used
to prevent noise because even when there is no audio input, the audio line-in
produces non-zero values due to noise. This caused unwanted random modulation on the
screen. This issue was solved by continuously averaging the absolute value of
the input over a half second period which acts as a low pass filter. If this
average is below a certain threshold, the input is considered zero. We also
threshold the absolute value of the filter output to ensure that the modulation
used for drawing is not too hectic. This makes it easier to identify drum beats
in the signal. This can be easily illustrated in Matlab. The following figures show the original
input, the low pass filtered input, and the thresholded low pass filtered
input. The peaks in the figure where a threshold is used correspond very
closely to the drum beats in the music. The resulting signal can be used
successfully to create audio visualizations which are in sync with the music.
In general, this scheme allowed us to isolate drum beats from the low pass
filter, voice and guitar from the band pass filter, and cymbal beats with the
high pass filter.
Figure 3: Raw audio input.
Figure 4: Low pass filtered
Figure 5: Low Pass filtered with
threshold
Lastly,
to implement a bar visualization scheme, the filter with a threshold output was
run through a look up table (LUT) to associate it with a bar height. The final
place where the audio input signal is used besides the visualization module is
in the height mapping process. The three filter range outputs are also put
through the height mapping process as well. The first step for all four of the
signals to be height mapped is to send them all through an absolute value unit.
Each absolute value unit makes sure the highest order bit is zero or that each
output from the absolute value unit is positive. These outputs are then fed
into firstHbit height mapping module. This module finds the highest order bit
that is a one and then sets the corresponding mapping to a pixel amount
vertically on the screen. The mapping computed here is used to send data to the
VGA controller that is coordinate specific and is described below in the simple
visualization section.
Audio
Codec
The audio codec used for this project
included five files which were AUDIO_DAC_ADC.v, I2C_AV_Config.v,
I2C_Controller.v, Reset_Delay.v, and VGA_Audio_PLL.v. The use of this hardware
was to be able to send and receive sixteen bit signals from the line out and
line in ports on the DE2 board. The input audio signal is run into the DE2
board for calculation and then can be output again by the user on the speakers
in lab so both listen and watch the music unfold in front of you.
VGA
Controller
The VGA controller used for this
project included four files VGA_Controller.v, VGA_Param.h, Reset_Delay.v, and
VGA_Audio_PLL.v. The reset delay and PLL files are duplicate files used between
both the audio codec and the VGA controller. The VGA controller had a clock
that was used to coordinate the cellular automaton drawing. Also the VGA
controller’s current x and y coordinates were used to place pixels to of a
certain color on the screen. If the coordinate values were in between
particular ranges then a certain color scheme could be used to fill in the LCD
display. The pixel values were read into the VGA controller using the mVGA_R,
mVGA_G, and mVGA_B tens bit signals.
SRAM
The SRAM in this project is
implemented as a bunch of wires in the top module. The SRAM_ADDR is set using
the eighteen bit addr_reg register which is assigned by the Cellular automaton
visualization unit. The SRAM_DQ is either tri-stated to read out of memory or
set to the sixteen bit data_reg register to write the value to memory. The
write or read functionality is done with the we register which dictates whether
a write to memory is enabled or not. The rest of the wires, such as SRAM_UB_N,
SRAM_LB_N, SRAM_CE_N, and SRAM_OE_N are set to zero. The SRAM is used for
writing an image to the SRAM and then reading it out onto the VGA display using
the Cellular automaton visualization unit.
Cellular
Automaton Visualization
The Cellular Automaton Visualization
is an instantiated processing unit in the top module since the attempt to place
it in separate module was unsuccessful. Towards the beginning of this unit is
where the reset wire is assigned. The reset is set to ~KEY[0] so that the
entire system can be restarted based on the users input. After the reset wire
there is one other wire instantiated which is x_low_bit which is used for the
pseudo random number generator. The pseudo random number generator which takes
a thirty one bit registers (x_rand) and xors the thirteenth and twenty seventh bit
together and shifts this value in the bottom of the x_rand. This pseudo random
number generator is used to instantiate a random first line for the cellular
automaton initial condition to be used to progress the cellular automaton
across the screen. The registers created for this visualization were addr_reg,
data_reg, we, state, lock, rule, randinit, x_walker, y_walker, and sum. The
addr_reg is eighteen bits and used to send address to the SRAM module. The
data_reg is sixteen bits and used to send data to the SRAM over the SRAM_DQ
bus. The we register is used to dictate the SRAM_WE_N wire and can tell the
SRAM whether or not to write the value on the data bus or not. The state
register is four bits and is used to move through the state to draw the current
cellular automaton image. The lock register is one bit and used to lock in a
calculation of another cellular automaton pixel. The rule register is eight
bits long and is used to dictate the current cellular automaton rule to
implement. The randinit one bit register is used to tell the visualization
scheme to start with a random initial condition or not. The x_walker and
y_walker registers are both eight bits and are used to traverse the SRAM to
write values into SRAM so they can be read appropriately and sent to the VGA
display. The final register, sum, is a three bit register which is used to
index into the rule to figure out if the pixel currently being looked at is to
be colored or made black.
The Cellular Automaton function runs
as an always block on the posedge of the VGA_CTRL_CLK and the first thing done
in this section is to sample the audio in and bass, cymbal, and the voice filtered
audio signals. These are sampled at both five bits and fifteen bits. These
values are used later on for color schemes to be written to the SRAM for
display on the VGA display. Upon reset the address register is set to the current
coordinates of the VGA controller. The we, data_reg, and rand are set to zero. If
the randinit is high or then start the x_walker and y_walker either start in
the top left or over by one pixel to draw the intial condition respectively. The rule on reset is set to one and the state
is set to test1. If reset is not pressed then the module will check to see if randinit
is pressed and the rand register is high then we assign a random sequence of
pixels to the first line of the LCD display. A random line is done by checking
the highest bit in the x_rand register and if one it places color in the pixel location
and otherwise it makes the pixel black. After the addr_reg and data_reg are set and we
is set to write the value will be written and this short section will increment
x_walker until it reaches the end of the line and resets the x_walker and y_walker
to the top left corner at (1,0) and sets the randinit low and we high to stop
writing memory. If rand is not high then a single pixel in the center of the
screen is written as another initial condition possibility. The data written in
this cellular automaton is not white or black pixels but pixel color is chosen
either from the current audio signals or from a pixel controller unit but when
a pixel is filled in the most significant bit is still written in as one and
that is used to check for how to fill in the next line on the screen.
After the randinit section the main
state machine can be seen that is run when either the VGA vertical and
horizontal sync is active low which reduces the jitter in the image. The state
machine then begins where it enters the state test1. This state does not allow
a memory write, sets the lock bit high so we know a pixel is being calculated,
the sum is reset to zero, the addr_reg is set to the {x_walker, y_walker}, and
finally the state is set to test2. In test2 we check the lock bit and if it is
not high then we return to start test1. If the lock bit is set then we place
the most significant bit of the SRAM_DQ into sum[1] for the first part of the
rule offset. The addr_reg is set to {x_walker-1, y_walker} and then the state
is set to test3. In test3 Once again the lock bit is tested similarly as
before. Once again the SRAM_DQ’s most significant bit is checked and place into
sum[2]. The addr_reg is set to {x_walker+1, y_walker} and state is moved to
test4. In test four we once again do the lock bit and then SRAM_DQ’s most
significant bit is placed in sum[0] and then the state is change to
draw_walker. In draw_walker we also check the lock bit and if it is set then we
set a memory write the addr_reg is set to {x_walker,y_walker+1}. Next the rule
is offset with sum (rule[sum])and if it is one then a pixel combination is written
into SRAM based on what the user selected. If the user selectes zere, one, two,
three, or four the pixel value written is either sample of all three filter
outputs, base filter output, cymbal filter output, voice filter output, or
audio inputs. If none of the options before are selected then a pixel
controller output is written to SRAM. If the sum offset into rule is not one
then a black pixel is written to SRAM. If the lock bit is not set then the state
machine remains in the draw_walker state but if a pixel is written to memory
then the update_walker state is entered where the x_walker and y_walker are
incremented appropriately across the screen. The x_walker is incremented by one
if it is less than 318 and then test1 is returned to. If the x_walker has
reached the end of the line or the value 318 then the y_walker is increment if
it is less than 237. The x_walker and y_walker are incremented as such until
they reach the end of the screen where the user_wait state is entered. In the
user_wait state if the user has selected this visualization then SW[1] &
SW[12] will be set high. The SW[1] is to select the CA module and the SW[12] is
to pause the progression if a cool image has appeared but that is a subjective
component on the user end. Also in user wait state the number of CA’s drawn is
larger than the maxPeriodLength then it is time to draw a new CA on the screen.
The countCA is set to zero and if SW[2] is high then the rule simply increments
otherwise the rule is dictate but bits 20 to 13 of the maxPerLength register. If
the rule is the max value and SW[2] is high then the rule is reset to one but
if not then the maxPerLength bits are used to dictate the rule. After this the x_walker and y_walker are reset
to zero. If rand is high then randinit is set and state is returned to test1. If
countCA has not reached the maxPeriodLength then this module remains in the
user_wait state until the timer has terminated. Finally if the reset, randinit,
or (~VGA_VS | ~VGA_HS) conditions are not met the CA sets the lock bit to zero,
sets the memory to read, and set the address register to the coordinates from
the VGA unit. This module will display CA’s at the beats of audio input and
images of this can be seen below in the results section.
Draw
Bars
The second visualization module
included in this project is draw bars which essentially shows the progression
of the audio codec inputs over time. The draw bars module has a lot of inputs
as it was actually capable of being placed in a sub module. The inputs into
this module are iHeight, iX, iY, iVGA_VS, iVGA_HS, CLK, VGACLK, AUDCLK, CLK27,
audIn, bass, cymbal, voice, RST, period, bassH, cymbalH, voiceH, and sigSel. The
iHeight, bassH, cymbalH, and voiceH are the all height mapping of the
audio_inL, the output from the bass filters, the cymbal filters, and the voice
filters after being run through the height mapping module. The iX and iY inputs
are the current coordinates coming from the VGA controller and are used to
detect which region we are currently writing to. The iVGA_VS and iVGA_HS are
the vertical and horizontal sync signals of the VGA controller and are used to
reduce jitter, if possible, and know when to redraw the screen. The CLK is the 50 MHz clock input. The VGACLK
is the VGA _CTRL_CLK input. The AUDCLK is the AUD_DACLRCK clock input. The
CLK27 is the CLOCK_27 clock input. The audIn, bass, cymbal, and voice inputs
are the sixteen bit audio signals from the audio input signal or one of three
filters. The RST is the reset from ~KEY[0]. The period is the period of the current
waveform. The outputs from this module are the state which was used for
debugging and the three ten bit VGA color outputs for red, green, and blue.
There are also a large number of
wires and register declared in this module. The wires red, green, and blue are
used for output from the pixel controller module and placed into the output to
the VGA controller if the current coordinates of the VGA controller wants are
to be colored. The next on the set of wires is one hundred one bit c wires
which are used for detection to see if the VGA controller is currently viewing
the coordinates within one of the columns to be drawn. After the declaration of
the hundred column wires there is the instantiation of one hundred ten bit
height registers which are used to keep track of the current magnitude of the
waveform and shift that magnitude across the screen as time increases. There is
one module instantiated inside of the draw bars and that is the pixelController
which is used to cycle through pixel schemes to keep the display fresh and new
all the time. After the instantiation of the pixelController all of the column
registers are assigned based on the current coordinates from the VGA
controller. Each column wire checks to make sure the y coordinate is above the
height register value and the x coordinate is between the six pixel bound
placed on the current column. There are
also two other wires used in this module to create eyes on the screen. The eyes
are two rectangles near the top of the screen and their condition is modified
based on either the bottom four bits of height_reg10 or height_reg20 depending
on whether it is eye1 or eye2. The conditions checked for the eyes vary the
rectangles size with each sample to pace their flashes with the music sampling.
The main part of this visualization
module is the always block on the positive edge of the 50 MHz clock. In this
section if the reset is high then all the height registers are set to zero and
the draw_state is set to init. If the reset is not high then a sampleCount is
incremented by one on each positive edge of the clock. In the init state if the
sampleCount is large than the bottom fourteen bits of the period then new
samples of the audio signals are taken. Also the first height register
(height_reg0) is set to one of the four height maps inputted into this module. If
the user selection is zero, one, two, or three then the height register used is
one for the audio input signal, the bass filter output, the cymbal filter
output, or the voice filter output respectively. The rest of the init state is
shifting all the registers values up one register which allows for the
progression of height across the screen. Finally the draw_state is set to
color. Then the color state is entered where we check if one of the one hundred
column conditions has been met or one of the eye conditions has been met and
not when the y coordinate from the VGA controller is divisible by ten. The
check to make sure the y coordinate is not divisible by 10 makes the bars
discretely different and significantly easier to draw. If this condition is met
then the current location from the VGA controller is shaded in with a color
which depend on the user input from SW[10:8]. If the switch value is zero then
the pixel controller values are outputted and if a value that is not checked
comes in then the pixel controller values are outputted. If the switch value is
one, two, three, or four then the audio input signal, bass filter output,
cymbal filter output, or voice filter output are used to output pixel values
respectively. In each case the red is set to the top ten bits of the signal
excluding the sign bit, the green is set to the inverse of the 12 to 3 bits,
and the blue is set equal to the bottom ten bits. If one of the eye conditions
are met and the SW[10:8] is zero then the pixel controller values are used with
eye1 using the inverse of blue and eye2 using the inverse of green. If the eye1
and eye2 have five, six, or seven as the selected input then top ten bits
without the sign bit are used in the following inverted combinations: bass,
cymbal, voice and cymbal, voice, bass and voice, bass, cymbal respectively. If
a column or eye condition is not met then a black pixel is sent to the VGA
controller. Finally in this module we wait in this state until the vs_sig is
set high and then the state moves back to init. The vs_sig register is set to
note the completion of the screen drawing which help remove as much jitter from
the screen as possible. The vs_sig is set using another state machine on
vs_state which waits for the falling edge of the VGA_VS clock to set vs_sig
high and then on the next cycle when it goes to state one sets the value back
to zero which allows for all the height registers to shift by one and then the
screen is drawn. Once the VGA_VS goes high again the state goes back to waiting
for the VGA_VS to fall again before shifting the height registers. At the end
of this module there are three assignments to output the pixel values on oR,
oG, and oB. This module successfully draws the height of the current signal
selected across the screen with two fluctuating eyes. Images of this can be
seen in the results section below.
Simple
Visualization
In the filtering section above
precise visual synchronization was a direct goal as part of this project. The
more complicated abstract visuals seen in the high level design worked out very
well but for precise coordination simpler visuals were needed. The simpler
visuals were drawn using a module similar to the draw bars module explained
above. For the simple visualization module which included the bars module but
in the simple module there were only twelve columns that were used and made a
simpler version of the draws bars seem above that followed a low passed version
of the height mapping. Another visualization scheme used was to draw a floating
box on the screen. On each run through of the draw bars state machine the
current x. On the other hand the y coordinate was added to by a larger quantity
based on the threshold of the music. Essentially the purpose was to have a box
gently float back and forth horizontally and when the beats passed over a
threshold the y coordinates of the box would be boosted and then slowly fall
again when the music did not surpass the threshold. This gave a very good
measure of the bass of the music. One final simple scheme used in this lab was to
create a single box in the center of the screen and fill it in with green
color. The coloring in the box varied, however, with the high frequency of the
music so you could get a feeling of the energy of the high frequencies in the
music being played. The code for this simple visualization can be found in the
appendix.
Box
Visuals
The third visualization module used is
the box visualization which shows the magnitudes of the audio input signal and
the output of all three filters implemented in the top module. The inputs into
this module are reset, CLK50, AUDCLK, VGA_VS, VGA_HS, audIn, cymbal, bass,
voice, coordX, coordY, and period. The reset is the reset from ~KEY[0]. The
CLK50, AUDCLK, VGA_VS, and VGA_HS are 50 MHz clock, the audio clock, and the
vertical and horizontal sync of the VGA respectively. The audIn, cymbal, bass,
and voice inputs are all sixteen bit audio signals from the audio codec and
three filters. The coordX and coordY or
the current coordinates from the VGA controller. Finally, period is the current
value of maxPerLength from the period calculator. This module only has three
outputs which are red, green, and blue which are all ten bit pixel values. The
boxVisual module has a number of registers called state, sample, sampleCymbal,
sampleBass, sampleVoice, region, redValue, greenValue, blueValue, and audCount.
The audCount is used to count a larger number of clock cycles before sampling
the audIn, cymbal, bass, and voice signal again to make the visuals do not move
too rapidly to destroy the user experience. The sample, sampleCymbal,
sampleBass, and sampleVoice are all the registers where the current samples are
kept for each of the respective input signals. The region register is used to
tell which region on the screen the VGA controller is currently traversing.
Where the VGA controller is will dictate what the pixel values that are
outputted will be. Finally the redValue, greenValue, and blueValue are all ten
bit registers that are set depending on the current region and output from the
module to the VGA controller. Finally
this module has twelve wires which are four red lines, four green lines, and
four blue lines which are used for the different color outputs of the pixel
controller to set four different colors depending on the region. The r0, r1,
r2, and r3 wires correspond to regions zero, one, two, and three which really
correspond to audio input signal, bass filter out, cymbal filter out, and voice
filter out.
The main part of this module is run
on the positive edge of the 50 MHz clock and the first item in this block is the
sampling section which was described above with the audCount. Next checking the
reset the state is set to locate. If the reset is not high then the locate
state is entered. In the locate function the VGA screen is divided up into a
grid of rectangle that are each 35 by 48 (y, x) pixels in size with grid blocks
on the end truncated if necessary. The purpose of locate is to set the register
region to know where we are on the screen. On top of the grid detection there
are four large concentric rectangles on the screen. The outer most rectangle
visualizes the audio input signal, then the bass filter output, then cymbal
filter output, and finally in the center and smallest voice filter output. For
each location check we first check what our current X coordinate from the VGA
controller is. Then after the X coordinate is checked the Y coordinate is
checked and from there we can tell which region we are in. The region can take
one of four values (but default cases are provided for assurance) in which zero
refers to the audio input signal, one refers to the bass filter output, two
refers to the cymbal filter output, and three refers to the voice filter
output. To add some variability in the regions
the current column corresponding signal has its four most significant bits (not
the sign bit) subtracted from the bounds of the column. This allows for the
thickness of each column to change. Furthermore the top and bottom rows of each
section also have the same top four bits subtracted from them. As a result each
of the four concentric rectangles changes their size differently depending on
the magnitude of their respective signal. Once the region register has been set the
state moves to color in which a case statement is used on the region. Depending
on the region a different color from a different pixel controller is used to
shade in that region. Not only do you have four different regions changing in
width and height differently but they also change in color differently. After
the appropriate color is placed in the redValue, greenValue, and blueValue
registers then the state goes back to locate. If none of the four regions are
satisfied the VGA displays black. The ten bit pixel values are output to the
top module and into the VGA controller.
Pixel
Controller & Pixel Variation
The three visualization units each
used this unit’s outputs to for color the pixel values to output to the VGA
controller. The goal of this module is to cycle through a variety of schemes
and output a long sequence of pixel values that do not repeat frequently. The
inputs into this module reset, VGA_VS, VGA_HS, CLK, CLK27, AUDCLK, schemeReset,
audIn, and periodIn. The reset is the ~KEY[0] from the top module. The VGA_VS,
VGA_HS, CLK, CLK27, and AUDCLK are all basic sync or clocks. The schemeReset
however is the value that the pixel controller sets to its schemeCycle register
when the hardware is reset. The schemeReset value is used so the controller can
start offset within the sequence of pixel values from another pixel variation
unit. The audIn in the audio input signal and the periodIn is the period of the
current audio signal from the period calculator. This module has three outputs
of red, green, and blue which are the pixel values to whatever module
instantiated it. The module also has three wires (redValue, greenValue, and
blueValue) that grab the pixel values from the pixel variation unit. This module does have a number of registers
called wtPrd, realPeriod, schemeCycle, and schemeCount. The wtPrd dictates the
current wait period selection for the pixel variation unit. The real period is
the period sent to the pixel variator which compensates for the change in color
taking 2^7 cycles and shifts the period down by that much to maintain the
colors and bass beat synchronization. The schemeCycle is the current scheme
wanted from the pixel variation unit. The schemeCount is the number of clock
cycle until the period is reached to increment the scheme to be sent to the
pixel variator.
The main chunk of this unit occurs
in the 50 MHz always block on the positive edge where is reset is pressed the
schemeCount goes to zero and the schemeCycle is set to the schemeReset value. If
the reset is not pressed then the schemeCount increments until it is larger
than eight times the period input which allows the user to enjoy a scheme for a
long period of time before changing the scheme. Once the schemeCount exceeds
its value it increments the schemeCycle by one and checks to see if the
schemeCycle is large than 254 and if it is the schemeCycle is set to zero. Also
when the schemeCycle reaches its last value the wait period is changed. The
wtPrd is incremented which allows for a different count time in the pixel
variation unit. The final operation the
pixel controller unit is to shift the periodIn down.
The pixel variation unit is similar
to the pixel controller unit in that it outputs the red, green, and blue pixel
values. The inputs into this unit at reset, VGA_VS, CLK, scheme, wtPer, and
period. The only inputs that are new here are the scheme and wtPer. The scheme
is the schemeCylce from the pixel controller and the wtPer is the waiting
period selector from the pixel controller. The scheme value is then dissected
into its meaningful values. Reverse, stat, alt, thirdVal, and mode are
extracted from the following from scheme as scheme[4], scheme[1], scheme[0],
scheme[3:2], and scheme[7:5] respectively. The pixel values in this unit are
set on the positive edge of the clock. Upon reset the count and all pixel
registers are set to zero. If the reset is not set and when the VGA_VS is low
the scheme values are extracted and then parsed into the pixel value wanted. First
the wtPrd chooses between how long to count clock cycles till outputting new
pixel values to slow the change in color or else it would change too fast and
make the users eyes hurt. After the wait period is selected the mode case cased
which dictates one of the following schemes in order from zero to seven: (red up, green down), (blue up, red down),
(green up, blue down), (blue up, green down), (green up, red down), (red up,
green up), (red up, blue up), and (green up, blue up). Once a mode is selected
we wait for the counter to increment past countMax. Once the countMax is
surpassed the first color is either added or subtracted depending if reverse is
set. Next if the scheme dictates that the second color is stationary that value
is checked. If the second color is to be stationary then the second color will
cycle by modulo 1000 by increments of 200 if the alternate value is high
otherwise it is not manipulated at all. If the second color is not to be
stationary the reverse is checked again and the second color is either added or
subtracted appropriately. If the second color is not stationary then the third
color (third color being the one note mentioned in the modes listed above) is
checked as to whether it should alternate or be set by the thirdVal register.
If the alternate bit is set high then the third color cycles through module
1000 by increments of 200 else the thirdVal case statement dictate the current
value as either zero, 250, 500, or 750. This logic is simply repeated for all eight
modes and then the red, green, and blue registers are outputted on wires and eventually
to the VGA controller for one’s viewing pleasure.
Software
There
was no software used in the functionality for our project but Matlab code was
used to generate the Draw Bars module since it involved a lot of repetitive
lines be created. See the appendix for this code.
Testing
Hardware
The assembly of the hardware for our
project implementation involved quite a few debugging techniques. The filtering
part of the project had several ways to test whether it worked or not. The
signal generator was used to input a signal with a known frequency and it was
passed into the DE2 board using the audio codec. Once the signal was inside the
FPGA it was victim to being manipulated by a large number of filters. Many
filters were used and tested and the outputs on the audio codec output were
switched using the switches on the DE2 board. Two signals could be checked at
the same time using the right and left channels on the output. The signals that
were checked on the line out were put into the oscilloscope to see what they
looked like. The value of the signal could be display on the red LEDs. The
signal generator was also used at this point to confirm how good the cutoffs
were and whether the filters were actually working. For example a 47 Hz wave
was place on the input channel and was barely seen after the cymbal and voice
filters. Although it was still seen after the bass filter.
The period calculation unit also
used a similar technique. In order to confirm the functionality of the period
calculator the signal generator output a known frequency and as a result the
period could be calculated and the order of magnitude for the number cycles
could be found. It was found at first that doing only two zero crosses only resulted
in the half period so three zero cross measurements were needed to get the same
order of magnitude for our period calculations. The period length was also
output on the HEX displays so the value could be updated when the frequency was
changed. Indeed when the frequency increased the period displayed decreased. It
was also discovered that some error could occur in measuring the period as down
sampling from audio rate to one thousand hertz could sometimes shift the zeros
around so max periods were kept for more accuracy.
When first trying to use the audio
codec and VGA controller modules it was necessary to use the red LEDs, the
green LEDs, the switches, and the HEX displays to be able to display as much
information as possible. Problems experienced with these units were undeclared
signals and clocks that were required to drive the controlling units. Once these
modules work the LEDs and hex displays were still used to display information
about the VGA display being updated. For example the Cellular automaton visualization
wouldn’t work at first so the coordinates were put on the red LEDs and the
state on the green LEDs and it was seen that incrimination of the address
halted part way through execution which turned out to be a side effect of
having moved the logic into a sub module. There was quite a bit of wasted time
during this lab in attempting to take logic that worked perfectly fine in the
top module and trying to move that logic into a sub module and having it no
longer work. The filters had a known problem of a critical timing error but
this did not show for other unit such as the Period Calculator and Cellular
Automaton modules that were attempted. Due to the lack of time these large
sections of code of were left in the top module. The oscilloscope was also used
here to see if the CIC module was work in a sub module but it appeared not to
be. Also much time was spent change various critical values inside certain
modules to see how the display would change or how closely synchronized the
music was with the visualization on the LCD display.
When creating the visualization
modules it was very helpful to try simple algorithms at first and check how
they looked visually using the VGA controller and LCD display in the lab. Numerous
additions could be made to visualization modules and displayed on the LCD
display to fine tune and ensure the correct behavior. Also the use of speakers
in the lab allowed us to see that the music was synced up fairly well with the
visualizations. The final form of testing that was used for logic that could
not be moved to sub modules and for strange behavior over the entire board Signal
Tap logic analyzer was used. The signal tap logic analyzer uses M4k blocks to
store the values of signals on the FPGA over time. As a result I could keep
track of how some of my modules were either not incrementing correctly or a
variable was being set incorrectly. Particularly when there are SRAM and VGA
display issues Signal Tap will help find the problem quickly.
Software
No software was used in our project
implementation. The software used was matlab script to write verilog which
contained all print statement so if there was an error it was printed in the
console and visibly correctible.
Results of Design
We
successfully implemented four different visualizations, depicted in the figure
below. Each visualization runs smoothly
with variations dictated by the audio input. The “boxes” visualization consists
of several boxes whose size and color is modulated by the audio. Cellular
automata visualization draws a random cellular automata rule on a periodic
basis depending on the bass frequencies in the audio input. The bars visualization draws 100 bars, each
representing a past sample of the audio input. It also has two boxes near the
top of the screen which are intended to appear like “eyes” whose size is
modulated by the audio amplitude. In
addition, the color is periodically altered. We also have a simple, single bar
visualization. This visualization is intended to show how our internal
filtering facilitates video synchronization with the audio. In addition to the
bar visualization there is also an LED visual that flashes with the bass beat.
One final visualization that moves a single square around the screen back and
forth in the horizontal direction. In the vertical direction the square will go
higher based on the bass beat and slowly falls when there is no bass in the
incoming audio signal.
The boxes visualization contains
some small visual artifacts (not visible in the figure) but otherwise each visualization
is displayed as desired. The filters used performed adequately. We were able to
extract bass, voice/guitar, and cymbal beats relatively well. Combined with
thresholding, our filtering displays relatively accurate synchronization with
the music beats. This is especially visible in the single bar visualization. Our project did not require safety
considerations nor did it cause interference with other designs in the lab. The
resulting project is usable by anyone, simply connect audio input to the board
and use the switches to select a visualization scheme.
Figure
6: Visualizations – Boxes (Left) – Cellular Automata (Right)
Figure
7: More Visualization – Bars (Left) – Single Bar (Right)
Figure
8: Visualization - Bars (left) – Cellular Automaton (right)
Figure
9: Visualization – Cellular Automaton (left) – Box Visual (right)
Figure
10: Visualization – Cellular Automaton on both screens
Conclusion
Our
goal was to implement audio visualization on the Altera DE2 board. Overall, we
have achieved a satisfactory end result.
Six different visualization schemes were implemented: two amplitude
modulated bar schemes, one LED mimic, single box, beat triggered cellular
automata, and amplitude modulated boxes. In addition, we implemented a
filtering scheme to improve visual and audio synchronization. Our filtering schemes utilized both period
and amplitude measurements.
Given
more time, we would have liked to explore more sophisticated filtering schemes.
We found that for complex visualizations, it was difficult to synchronize the
music with the drawing. With an improved filtering scheme, we may have been
able to synchronize better. For instance, it would be interesting to explore
filtering schemes intended to isolate single instruments from music. More time
would have also been helpful because the number of visualization schemes is
essentially endless and it would have been enjoyable to spend more time
implementing more algorithms.
There
are no standard schemes for audio visualization. In fact, we did not find
adequate documentation on any specific audio visualization implementation.
However, we can compare our audio visualization to others. The Atari Video
Music device developed by Atari Inc. in 1976 was one of the first audio
visualization devices. We believe that our implementation is comparable to the
Atari Video Music device.
Regarding
intellectual property, our IIR filters were adapted from those provided on the
ECE5760 website. Our code also uses the audio codec driver and VGA driver from
the ECE5760 website. Finally, there are no legal considerations to address
regarding our project.
APPENDIX
/////////////////////////////////////////////////////////////
/////////
Audio Visualization ///////////////////////////////
////////
ECE 5760 - Final Project ///////////////////////////
////////
Michael Lyons - mpl56 //////////////////////////////
////////
Darbin Reyes - der34 ///////////////////////////////
/////////////////////////////////////////////////////////////
wire
[31:0] mSEG7_DIG;
reg [31:0] Cont;
wire VGA_CTRL_CLK;
wire AUD_CTRL_CLK;
wire
[9:0] mVGA_R;
wire
[9:0] mVGA_G;
wire
[9:0] mVGA_B;
wire
[19:0] mVGA_ADDR; //video
memory address
wire
[9:0] Coord_X, Coord_Y; //display coods
wire DLY_RST;
assign TD_RESET = 1'b1; // Allow
27 MHz input
assign AUD_ADCLRCK = AUD_DACLRCK;
assign AUD_XCK = AUD_CTRL_CLK;
//modules
needs for Audio codec and VGA
Reset_Delay r0 (.iCLK(CLOCK_50),.oRESET(DLY_RST) );
I2C_AV_Config
u3 ( // Host
Side
.iCLK(CLOCK_50),
.iRST_N(KEY[0]),
// I2C Side
.I2C_SCLK(I2C_SCLK),
.I2C_SDAT(I2C_SDAT) );
VGA_Audio_PLL
p1 ( .areset(~DLY_RST),.inclk0(CLOCK_27),.c0(VGA_CTRL_CLK),.c1(AUD_CTRL_CLK),.c2(VGA_CLK) );
//////////////////////////////////////////////////////////
//
output to audio DAC
wire
signed [15:0] audio_outL, audio_outR ;
//
input from audio ADC
wire
signed [15:0] audio_inL, audio_inR ;
AUDIO_DAC_ADC
u4 ( // Audio
Side
.oAUD_BCK(AUD_BCLK),
.oAUD_DATA(AUD_DACDAT),
.oAUD_LRCK(AUD_DACLRCK),
.oAUD_inL(audio_inL),
// audio data from ADC
.oAUD_inR(audio_inR),
// audio data from ADC
.iAUD_ADCDAT(AUD_ADCDAT),
.iAUD_extL(audio_outL),
// audio data to DAC
.iAUD_extR(audio_outR),
// audio data to DAC
// Control Signals
.iCLK_18_4(AUD_CTRL_CLK),
.iRST_N(DLY_RST),
.isel(SW[17])
);
//////////////////////////////////////////////////////////
VGA_Controller u1 ( // Host
Side
.iCursor_RGB_EN(4'b0111),
.oAddress(mVGA_ADDR),
.oCoord_X(Coord_X),
.oCoord_Y(Coord_Y),
.iRed(mVGA_R),
.iGreen(mVGA_G),
.iBlue(mVGA_B),
// VGA Side
.oVGA_R(VGA_R),
.oVGA_G(VGA_G),
.oVGA_B(VGA_B),
.oVGA_H_SYNC(VGA_HS),
.oVGA_V_SYNC(VGA_VS),
.oVGA_SYNC(VGA_SYNC),
.oVGA_BLANK(VGA_BLANK),
// Control Signal
.iCLK(VGA_CTRL_CLK),
.iRST_N(DLY_RST) );
//
assign VGA outputs
assign
mVGA_R = SW[1] ? {SRAM_DQ[14:10], 5'b0} : SW[0] ? barR : boxR;
assign
mVGA_G = SW[1] ? {SRAM_DQ[9:5], 5'b0} : SW[0] ? barG : boxG;
assign
mVGA_B = SW[1] ? {SRAM_DQ[4:0], 5'b0} : SW[0] ? barB : boxB;
///////////////////////////////////////////////////////////////
//
SRAM_control
assign
SRAM_ADDR = addr_reg;
assign
SRAM_DQ = (we)? 16'hzzzz : data_reg ;
assign
SRAM_UB_N = 0; //
hi byte select enabled
assign
SRAM_LB_N = 0; //
lo byte select enabled
assign
SRAM_CE_N = 0; //
chip is enabled
assign
SRAM_WE_N = we; //
write when ZERO
assign
SRAM_OE_N = 0; //output
enable is overidden by WE
//
reset wire
assign
reset = ~KEY[0];
///////////////////////////////////////////////////////////////
//boxvisual
instantiation /////////////////////////////////////
wire
[9:0] boxR, boxG, boxB;
//module
boxVisual(reset, CLK50, AUDCLK, VGA_VS, audIn, cymbal,bass,voice, coordX,
coordY, period, red, green, blue);
boxVisual
box1(reset, CLOCK_50, AUD_DACLRCK, VGA_VS, VGA_HS,
audio_inL,IIR4outL_cymbal2,IIR4outL_bass2,IIR4outL_voice2,Coord_X[9:1],Coord_Y[9:1],maxPerLength,boxR,boxG,boxB);
////////////////////////////////////
//
bar pixel values
wire
[9:0] barR, barG, barB;
//module
drawBars(iHeight,iX,iY,iVGA_VS,iVGA_HS,oR,oG,oB,CLK,VGACLK,AUDCLK,CLK27,audIn,RST,state,period);
//module
drawBars(iHeight,iX,iY,iVGA_VS,iVGA_HS,oR,oG,oB,CLK,VGACLK,AUDCLK,CLK27,audIn,RST,state,period,bassH,cymbalH,voiceH,sigSel);
drawBars
uBars(.iHeight(hbitamp), //draw bars
.iX(Coord_X),
.iY(Coord_Y),
.iVGA_VS(VGA_VS),
.iVGA_HS(VGA_HS),
.oR(barR),
.oG(barG),
.oB(barB),
.CLK(CLOCK_50),
.VGACLK(VGA_CTRL_CLK),
.AUDCLK(AUD_DACLRCK),
.CLK27(CLOCK_27),
.audIn(audio_inL),
.bass(IIR4outL_bass2),
.cymbal(IIR4outL_cymbal2),
.voice(IIR4outL_voice2),
.RST(~KEY[0]),
.state(blank),
.period(maxPerLength),
.bassH(bassHbit),
.cymbalH(cymbalHbit),
.voiceH(voiceHbit),
.sigSel(SW[10:6])
);
////////////////////////////////////////////////
/////////////
CA visualization /////////////////
////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//most
important vars to know about
wire
reset;
reg
[17:0] addr_reg; //memory address register for SRAM
reg
[15:0] data_reg; //memory data register
for SRAM
reg
we ; //write
enable for SRAM
reg
[3:0] state; //state machine
reg
lock; //did we stay in sync?
reg
[7:0] rule; // to store the CA rule
reg
randinit; //signal to init the first line to random black/white
reg
[30:0] x_rand; //shift registers for
random number gen
wire
x_low_bit; //rand low bits for SR
reg
[8:0] x_walker; //current position coords
reg
[8:0] y_walker;
reg
[2:0] sum; //neighbors state
///////////////////////////////////////////////////////////////////////
//right-most
bit for rand number shift regs
//your
basic XOR random # gen
assign
x_low_bit = x_rand[27] ^ x_rand[30];
///
pixel controller logic
wire
[9:0] CAR, CAG, CAB;
//module
pixelController(reset, schemeReset, CLK, CLK27, AUDCLK, VGA_VS, VGA_HS, audIn,
periodIn, red, green, blue);
pixelController
unit1(reset, 8'd16, CLOCK_50, CLOCK_27, AUDCLK, VGA_VS, VGA_HS, audio_inL,
(maxPerLength>>4), CAR, CAG, CAB);
//state
names for machines that draws automata
parameter test1=4'd1, test2=4'd2, test3=4'd3,
test4=4'd4,
draw_walker=4'd5,
update_walker=4'd6, user_wait=4'd7;
//state
names for machine tha copies bottom line to top line
parameter
cinit=4'd0, cread=4'd1,csave=4'd2, cwrite=4'd3;
reg
[31:0] countCA;
reg
rand;
reg
[4:0] bassColor, cymbalColor, voiceColor;
reg
[14:0] bassFull, cymbalFull, voiceFull, audioFull;
//
on VGA control clock run CA
always
@ (posedge VGA_CTRL_CLK) begin
bassColor <=
IIR4outL_bass2[15:11];
cymbalColor <=
IIR4outL_cymbal2[15:11];
voiceColor <=
IIR4outL_voice2[15:11];
bassFull <=
IIR4outL_bass2[14:0];
cymbalFull <=
IIR4outL_cymbal2[14:0];
voiceFull <=
IIR4outL_voice2[14:0];
audioFull <=
audio_inL[14:0];
if (reset) begin //synch
reset assumes KEY0 is held down 1/60 second
//clear
the screen
addr_reg
<= {Coord_X[9:1],Coord_Y[9:1]} ; //
[17:0]
we
<= 1'b0; //write
some memory
data_reg
<= 16'b0; //write
all zeros (black)
rand
<= 1'd0;
if(rand)begin
//init top line of screen to random black white
x_walker
<= 9'd0; //start at 0,0 to make sure every pixel is assign a random color
y_walker
<= 9'd0;
randinit
<=1'b1;
end else begin
x_walker
<= 9'd1; //otherwise start one pixexl to the right to force a black border
y_walker
<= 9'd0;
randinit
<=1'b1;
x_rand
<= 31'h55555555;//init random number generator to alternating bits
end
//get
rule from switches
rule
<= 8'd1;//SW[7:0];
state
<= test1; //first state
in drawing state machine
end
else if(randinit)
begin// assign the top line random colors if SW17 is high, else single dot at
top center
if(rand)
begin//random colors
if(x_walker
<=9'd319) begin//entire line
x_rand
<= {x_rand[29:0], x_low_bit} ; //update the x,y random number gens
addr_reg
<= {x_walker,y_walker}; //write to the pixels on the top line
we
<= 1'b0; //write
if(x_rand[30])
data_reg <= SW[3] ? {1'b1,bassColor,cymbalColor,voiceColor} :
{1'b1,CAR[9:5],CAG[9:5],CAB[9:5]} ; //white pixel
else
data_reg <= 16'b0; //black pixel
x_walker
<= x_walker+9'd1; //next pixel
end
else begin
x_walker
<= 9'd1;
y_walker
<= 9'd0;
we
<= 1'b1; //stop writing to mem
randinit<=
1'b0; //done drawing random line
end
end
else begin//single dot at top center
addr_reg <= {9'd160,9'd0} ; //init to single dot
//write
a white dot in the middle of the screen
we <= 1'b0;
data_reg <= {1'b1,
CAR[9:5],CAG[9:5],CAB[9:5]} ;
randinit<= 1'b0;
end
end else if ((~VGA_VS |
~VGA_HS)) begin //sync is active low //modify display during sync*/
case(state)
test1:
begin//read self
we
<= 1'b1; //no
memory write
lock
<= 1'b1; //set the
interlock to detect end of sync interval
sum
<= 3'b0; //init
neighbor state
addr_reg
<= {x_walker,y_walker};//read self
state
<= test2 ;
end
test2:
begin//check self and read left neighbor
if(lock)
begin//must check lock before reading to make sure the right value is read
we
<= 1'b1; //no memory write
sum[1]
<=SRAM_DQ[15];
//read
left neighbor
addr_reg
<= {x_walker-9'd1,y_walker};
state
<= test3 ;
end
else state <= test1 ; //otherwise start over because addr_reg was destroyed
by VGA controller
end
test3:
begin//check left neighbor and read right neighbor
if(lock)begin
we
<= 1'b1; //no memory write
sum[2]
<=SRAM_DQ[15];
//read
right neighbor
addr_reg
<= {x_walker+ 9'd1,y_walker };
state
<= test4 ;
end
else state <= test1 ;
end
test4:
begin//check right neighbor
if(lock)begin
we
<= 1'b1; //no memory write
sum[0]
<=SRAM_DQ[15];
state
<= draw_walker ;
end
else state <= test1 ;
end
draw_walker:
begin//light up cell in next generation
if(lock)
begin// if we got this far, then the sum var it correct so spin on the lock
until you get a chance to write
we
<= 1'b0; // memory write
addr_reg
<= {x_walker,y_walker+1'b1}; //cell below this one
if(rule[sum])begin
case(SW[5:3])
3'd0:
data_reg <= {1'b1,bassColor,cymbalColor,voiceColor};
3'd1:
data_reg <= {1'b1,bassFull};
3'd2:
data_reg <= {1'b1,cymbalFull};
3'd3:
data_reg <= {1'b1,voiceFull};
3'd4:
data_reg <= {1'b1,audioFull};
default:
data_reg <= {1'b1,CAR[9:5],CAG[9:5],CAB[9:5]} ; //pixel variator unit
endcase
end
else begin
data_reg
<= 16'b0 ; //black
end
state
<= update_walker ; //move to next cell
end
else begin
state
<= draw_walker;
lock
<= 1'b1; //set the
interlock to detect end of sync interval
end
end
update_walker:
begin//update the walker
we
<= 1'b1; //no mem write
//move
to next pixel
if
(x_walker<9'd318 & y_walker < 9'd237)begin
x_walker
<= x_walker+9'd1;
state
<= test1 ;
end
else if (x_walker == 9'd318 & y_walker < 9'd237)begin
x_walker
<= 9'd1;
y_walker
<= y_walker+9'd1;
state
<= test1 ;
end
else begin
state <= user_wait;//test1 ; //done, just loop
end
end
user_wait:
begin//wait for user to do something
if
(SW[1]&SW[12]) begin
countCA
<= countCA + 32'd1;
if
(countCA > (maxPerLength)) begin
countCA
<= 32'd0;
if
(SW[2]) begin
rule
<= rule + 8'd1;
end
else begin
rule
<= maxPerLength[20:13];
end
if
(rule==8'd255) begin
if
(SW[2]) rule <= 8'd1;
else
rule <= maxPerLength[20:13];
rand
<= ~rand;
end
x_walker
<= 0;
y_walker
<= 0;
if(rand)
randinit <= 1'd1;
state
<= test1;
end
end
else begin
//randinit
<= SW[4];
state
<= user_wait;
end
end
endcase
end else begin
//show
display when not blanking, which implies we=1 (not enabled); and use VGA module
address
lock
<= 1'b0; //clear lock if display starts because this destroys mem addr_reg
addr_reg
<= {Coord_X[9:1],Coord_Y[9:1]} ;
we
<= 1'b1;
end
end
//
assign the current rule to the green LEDs
assign
LEDG = rule;
assign
LEDR = SRAM_DQ;
//////////////////////////////////////////////
//Period
calculation that needs to be done in top module
//parameters
parameter
firstCross = 3'd0, secondCross = 3'd1, thirdCross = 3'd2;
parameter
firstSample = 3'd3, secondSample = 3'd4, thirdSample = 3'd5;
//registers
reg
clk1000;
reg
[2:0] state1000;
reg
[9:0] newMax;
reg
signed [15:0] sample1000, prevSample, hzCount;
reg
[31:0] periodCount, periodLength, maxPerLength;
reg
signed [15:0] modIn;
//wires
//wire
signed [15:0] CIC_out1;
wire
signed [15:0] oCIC;
//wire
signed [15:0] temp;
//outputs
reg
[31:0] period;
//
down sample to audio rate
CIC_N2_M1_16bit_fixed
f1(oCIC, modIn, CLOCK_27, AUD_DACLRCK, reset);
//
sample audio in at 27 MHz
always
@ (posedge CLOCK_27) begin
modIn <= audio_inL;
end
//
period calculation via zero crossing
always
@ (posedge CLOCK_50) begin
// bass beat finding
periodCount <=
periodCount + 32'd1;
hzCount <= hzCount +
16'd1;
// create a 1000 Hz
signal to alias all high freqencies to get
// accurate measurements
on the lowest frequencies
if
(hzCount>16'd25000) begin
hzCount
<= 16'd0;
if
(clk1000) begin
clk1000
<= 1'd0;
end
else begin
clk1000
<= 1'd1;
end
end
//if reset then set all
registers to zero
if (reset) begin
maxPerLength
<= 0;
prevSample
<= 0;
newMax
<= 0;
state1000
<= firstSample;
end else begin
case(state1000)
//
on high 1000 Hz take sample of CIC filter output
firstSample:
begin
if
(clk1000) begin
sample1000
<= oCIC;//CIC_out1;
state1000
<= firstCross;
end
end
//
wait for a sign change in the CIC output
firstCross:
begin
//
if there is a change from positive to negative go to next sample
if((prevSample>0)&&(0>sample1000))begin
periodCount
<= 32'd0;
prevSample
<= sample1000;
state1000
<= secondSample;
//
if there is a change from negative to positive go to next sample
end
else if ((prevSample<0)&&(0<sample1000))begin
periodCount
<= 32'd0;
prevSample
<= sample1000;
state1000
<= secondSample;
end
else begin // no change get a new sample
prevSample
<= sample1000;
state1000
<= firstSample;
end
end
//
on high 1000 Hz take sample of CIC filter output
secondSample:
begin
if
(clk1000) begin
sample1000
<= oCIC;//CIC_out1;
state1000
<= secondCross;
end
end
//
wait for a sign change in the CIC output
//
second cross for mid way through waveform
secondCross:
begin
//
if there is a change from positive to negative go to next sample
if((prevSample>0)&&(0>sample1000))begin
prevSample
<= sample1000;
state1000
<= thirdSample;
//
if there is a change from negative to positive go to next sample
end
else if ((prevSample<0)&&(0<sample1000))begin
prevSample
<= sample1000;
state1000
<= thirdSample;
end
else begin // no change get a new sample
prevSample
<= sample1000;
state1000
<= secondSample;
end
end
//
on high 1000 Hz take sample of CIC filter output
thirdSample:
begin
if
(clk1000) begin
sample1000
<= oCIC;//CIC_out1;
state1000
<= thirdCross;
end
end
//
wait for a sign change in the CIC output
//
third cross for full period measurement
thirdCross:
begin
//
if there is a change from positive to negative go to next sample
if((prevSample>0)&&(0>sample1000))begin
periodLength
<= periodCount;
newMax
<= newMax + 10'd1;
if(newMax
> 10'd1000)begin // get a new max period length
newMax
<= 10'd0;
maxPerLength
<= 32'd1000;
end else if(periodLength > maxPerLength) begin
// if new period is larger save it
maxPerLength
<= periodLength;
end
prevSample
<= sample1000;
state1000
<= firstSample;
//
if there is a change from negative to positive go to next sample
end
else if ((prevSample<0)&&(0<sample1000))begin
periodLength
<= periodCount;
newMax
<= newMax + 10'd1;
if(newMax
> 10'd1000)begin // get a new max period length
newMax
<= 10'd0;
maxPerLength
<= 32'd1000;
end
else if(periodLength >
maxPerLength) begin// if new period is larger save it
maxPerLength
<= periodLength;
end
prevSample
<= sample1000;
state1000
<= firstSample;
end
else begin // no change get a new sample
prevSample
<= sample1000;
state1000
<= thirdSample;
end
end
endcase
end//
end//
end always
//
assign which signal you want to output
reg
[15:0] audOut;
always
@ (posedge CLOCK_50) begin
case(SW[16:14])
3'd0:
begin
audOut
<= oCIC; // output the CIC filter
end
3'd1:
begin
audOut
<= audio_inL; // normal audio input
end
3'd2:
begin
audOut
<= IIR4outL_cymbal2; // cymbal filter output
end
3'd3:
begin
audOut
<= IIR4outL_bass2; // bass filter output
end
3'd4:
begin
audOut
<= IIR4outL_voice2; // voice filter output
end
3'd5:
begin
audOut
<= sample1000;
end
default
audOut <= 16'd0;
endcase
end
//
audio outputs assign to wires
assign
audio_outL = audOut;//CIC_out1;
assign
audio_outR = audOut;
//
max period length calculation counter displayed on red LEDs
//assign
LEDR = newMax;
///////////////////////////////////////////////////////////////////
///////////////////
absolute value unit ///////////////////////////
///////////////////////////////////////////////////////////////////
wire
signed [15:0] absoutL; // output of abs unit
wire
signed [15:0] absBass, absCymbal, absVoice;
abs
uabsL(absoutL, audio_outR, 4'd0,AUD_DACLRCK); //takes absolute value of input
abs
absbass(absBass, IIR4outL_bass2, 4'd0,AUD_DACLRCK);
abs
abscymbal(absCymbal, IIR4outL_cymbal2, 4'd0,AUD_DACLRCK);
abs
absvoice(absVoice, IIR4outL_voice2, 4'd0,AUD_DACLRCK);
///////////////////////////////////////////////////////////////////
//////////////////////
find the highest order bit /////////////////
///////////////////////////////////////////////////////////////////
//
highest order bit output
wire
[9:0] hbitamp, bassHbit, cymbalHbit, voiceHbit;
firstHbit
hb(absoutL[15:6],hbitamp,CLOCK_50); //bit quatize bar height
firstHbit
hbbass(absBass[15:6],bassHbit,CLOCK_50); //bit quatize bar height
firstHbit
hbcymbal(absCymbal[15:6],cymbalHbit,CLOCK_50); //bit quatize bar height
firstHbit
hbvoice(absVoice[15:6],voiceHbit,CLOCK_50); //bit quatize bar height
///////////////////////////////////////////////////////////////////
///////////////////////
7 segment displays ////////////////////////
///////////////////////////////////////////////////////////////////
HexDigit
h0(HEX0, maxPerLength[3:0]);
HexDigit
h1(HEX1, maxPerLength[7:4]);
HexDigit
h2(HEX2, maxPerLength[11:8]);
HexDigit
h3(HEX3, maxPerLength[15:12]);
HexDigit
h4(HEX4, maxPerLength[19:16]);
HexDigit
h5(HEX5, maxPerLength[23:20]);
HexDigit
h6(HEX6, maxPerLength[27:24]);
HexDigit
h7(HEX7, maxPerLength[31:28]);
/////////////////////////
Filter outputs declared /////////////////
wire
signed [15:0] IIR4outL_voice1,IIR4outL_voice2;
wire
signed [15:0] IIR4outL_cymbal1,IIR4outL_cymbal2;
wire
signed [15:0] IIR4outL_bass1,IIR4outL_bass2;
///////////////////////////////////////////////////////////////////
///////////////////////
cymbal filtering //////////////////////////
/////////////////Filter:
cutoff=0.5 ,cheby1 high //////////////////
///////////////////////////////////////////////////////////////////
IIR4_18bit_fixed IIR4L_cymb1(
.audio_out (IIR4outL_cymbal1),
.audio_in (audio_inL),
.scale (3'd1),
.b1 (18'hCA7),
.b2 (18'h3CD63),
.b3 (18'h4BEC),
.b4 (18'h3CD63),
.b5 (18'hCA7),
.a2 (18'h3FC41),
.a3 (18'h3A7AA),
.a4 (18'h3EE8D),
.a5 (18'h3F654),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
///////////////////////////////////////////////////////////////////
////////////////
Filter: cutoff=0.6 ,cheby1 low ///////////////////
///////////////////////////////////////////////////////////////////
IIR4_18bit_fixed
IIR4L_cymb2(
.audio_out (IIR4outL_cymbal2),
.audio_in (IIR4outL_cymbal1),
.scale (3'd1),
.b1 (18'h1682),
.b2 (18'h5A0A),
.b3 (18'h8710),
.b4 (18'h5A0A),
.b5 (18'h1682),
.a2 (18'h398AF),
.a3 (18'h395A5),
.a4 (18'h3EE6B),
.a5 (18'h3F6EC),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
///////////////////////////////////////////////////////////////////
/////////////////bass
beat filter//////////////////////////////////
/////////
Filter: cutoff=0.02 , cheby1 low ////////////////////////
///////////////////////////////////////////////////////////////////
IIR4_27bit
IIR4_bass1(
.audio_out (IIR4outL_bass2),
.audio_in (audio_inL),
.scale (3'd2),
.b1 (27'hF),
.b2 (27'h3E),
.b3 (27'h5D),
.b4 (27'h3E),
.b5 (27'hF),
.a2 (27'hF492E6),
.a3 (27'h6A0C0AB),
.a4 (27'hE0AA7A),
.a5 (27'h7CA00F9),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
///////////////////////////////////////////////////////////////////
//////////////////////////guitar/voice
filter//////////////////////
//////////////////
Filter: cutoff=0.05 ,cheby1 high ///////////////
///////////////////////////////////////////////////////////////////
IIR4_27bit IIR4_voice1(
.audio_out (IIR4outL_voice1),
.audio_in (audio_inL),
.scale (3'd2),
.b1 (27'h3426B9),
.b2 (27'h72F651C),
.b3 (27'h138E856),
.b4 (27'h72F651C),
.b5 (27'h3426B9),
.a2 (27'hE7331D),
.a3 (27'h6C586C9),
.a4 (27'hBED26A),
.a5 (27'h7D469AF),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
///////////////////////////////////////////////////////////////////
///////////////
Filter: cutoff=0.06 ,cheby1 low ///////////////////
///////////////////////////////////////////////////////////////////
IIR4_27bit
IIR4_voice2(
.audio_out (IIR4outL_voice2),
.audio_in (IIR4outL_voice1),
.scale (3'd2),
.b1 (27'hE5),
.b2 (27'h395),
.b3 (27'h560),
.b4 (27'h395),
.b5 (27'hE5),
.a2 (27'hE8252D),
.a3 (27'h6C15AFD),
.a4 (27'hC401F3),
.a5 (27'h7D26F62),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
///////////////////////////////////////////////////////////////////
endmodule
//top module
///////////////////////////////////////////////////////////////////
////////////////////
draw bars visualization //////////////////////
////////////////////////////////////draw
bars//////////////////////
module
drawBars(iHeight,iX,iY,iVGA_VS,iVGA_HS,oR,oG,oB,CLK,VGACLK,AUDCLK,CLK27,audIn,bass,cymbal,voice,RST,state,period,bassH,cymbalH,voiceH,sigSel);
//
parameters
parameter
init=4'd0, color=4'd1,eyeheight=10'd20,eyewidth=10'd60;
//
inputs
input
[4:0] sigSel;
input
[9:0] iHeight, bassH, cymbalH, voiceH; //height of bar
input
[9:0] iY; //VGA coordinates
input
[9:0] iX;
input
[31:0] period;
input
[15:0] audIn, bass, cymbal,voice;
input
CLK,RST,VGACLK, AUDCLK, CLK27;
input
iVGA_VS,iVGA_HS; //vga sync
//outputs
output
[3:0] state;
output
[9:0] oR,oG,oB; //vga colors
//wires
wire
eye1,eye2;
wire
[9:0] red, green, blue;
//
all column wires declared
wire
c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,c30,c31,c32,c33,c34,c35,c36,c37,c38,c39,c40,c41,c42,c43,c44,c45,c46,c47,c48,c49,c50,c51,c52,c53,c54,c55,c56,c57,c58,c59,c60,c61,c62,c63,c64,c65,c66,c67,c68,c69,c70,c71,c72,c73,c74,c75,c76,c77,c78,c79,c80,c81,c82,c83,c84,c85,c86,c87,c88,c89,c90,c91,c92,c93,c94,c95,c96,c97,c98,c99;
//registers
reg
[9:0] reg_R,reg_G,reg_B,x,y;
reg
[15:0] sampleAudio, sampleBass, sampleCymbal, sampleVoice;
reg
switchColor;
reg
[23:0] sampleCount;
reg
[3:0] draw_state;
reg
[9:0] redValue, greenValue, blueValue;
//
all heights registers declared
reg
[9:0] height_reg0;
reg
[9:0] height_reg1;
reg
[9:0] height_reg2;
reg
[9:0] height_reg3;
reg
[9:0] height_reg4;
reg
[9:0] height_reg5;
reg
[9:0] height_reg6;
reg
[9:0] height_reg7;
reg
[9:0] height_reg8;
reg
[9:0] height_reg9;
reg
[9:0] height_reg10;
reg
[9:0] height_reg11;
reg
[9:0] height_reg12;
reg
[9:0] height_reg13;
reg
[9:0] height_reg14;
reg
[9:0] height_reg15;
reg
[9:0] height_reg16;
reg
[9:0] height_reg17;
reg
[9:0] height_reg18;
reg
[9:0] height_reg19;
reg
[9:0] height_reg20;
reg
[9:0] height_reg21;
reg
[9:0] height_reg22;
reg
[9:0] height_reg23;
reg
[9:0] height_reg24;
reg
[9:0] height_reg25;
reg
[9:0] height_reg26;
reg
[9:0] height_reg27;
reg
[9:0] height_reg28;
reg
[9:0] height_reg29;
reg
[9:0] height_reg30;
reg
[9:0] height_reg31;
reg
[9:0] height_reg32;
reg
[9:0] height_reg33;
reg
[9:0] height_reg34;
reg
[9:0] height_reg35;
reg
[9:0] height_reg36;
reg
[9:0] height_reg37;
reg
[9:0] height_reg38;
reg
[9:0] height_reg39;
reg
[9:0] height_reg40;
reg
[9:0] height_reg41;
reg
[9:0] height_reg42;
reg
[9:0] height_reg43;
reg
[9:0] height_reg44;
reg
[9:0] height_reg45;
reg
[9:0] height_reg46;
reg
[9:0] height_reg47;
reg
[9:0] height_reg48;
reg
[9:0] height_reg49;
reg
[9:0] height_reg50;
reg
[9:0] height_reg51;
reg
[9:0] height_reg52;
reg
[9:0] height_reg53;
reg
[9:0] height_reg54;
reg
[9:0] height_reg55;
reg
[9:0] height_reg56;
reg
[9:0] height_reg57;
reg
[9:0] height_reg58;
reg
[9:0] height_reg59;
reg
[9:0] height_reg60;
reg
[9:0] height_reg61;
reg
[9:0] height_reg62;
reg
[9:0] height_reg63;
reg
[9:0] height_reg64;
reg
[9:0] height_reg65;
reg
[9:0] height_reg66;
reg
[9:0] height_reg67;
reg
[9:0] height_reg68;
reg
[9:0] height_reg69;
reg
[9:0] height_reg70;
reg
[9:0] height_reg71;
reg
[9:0] height_reg72;
reg
[9:0] height_reg73;
reg
[9:0] height_reg74;
reg
[9:0] height_reg75;
reg
[9:0] height_reg76;
reg
[9:0] height_reg77;
reg
[9:0] height_reg78;
reg
[9:0] height_reg79;
reg
[9:0] height_reg80;
reg
[9:0] height_reg81;
reg
[9:0] height_reg82;
reg
[9:0] height_reg83;
reg
[9:0] height_reg84;
reg
[9:0] height_reg85;
reg
[9:0] height_reg86;
reg
[9:0] height_reg87;
reg
[9:0] height_reg88;
reg
[9:0] height_reg89;
reg
[9:0] height_reg90;
reg
[9:0] height_reg91;
reg
[9:0] height_reg92;
reg
[9:0] height_reg93;
reg
[9:0] height_reg94;
reg
[9:0] height_reg95;
reg
[9:0] height_reg96;
reg
[9:0] height_reg97;
reg
[9:0] height_reg98;
reg
[9:0] height_reg99;
//pixelVar
unit1(reset, iVGA_VS, CLK, switch[10:8], switch[7], switch[6:5], switch[4:3],
switch[2], switch[1], switch[0], red, green, blue);
//pixelController(reset,
CLK, CLK27, AUDCLK, VGA_VS, audIn, periodIn, red, green, blue);
pixelController
unit1(reset, 8'd16, CLK, CLK27, AUDCLK, iVGA_VS, iVGA_HS, audIn, period, red,
green, blue);
//
all column values
assign
c0=iY > height_reg0 & iX>10'd0 & iX<10'd6;
assign
c1=iY > height_reg1 & iX>10'd6 & iX<10'd12;
assign
c2=iY > height_reg2 & iX>10'd12 & iX<10'd18;
assign
c3=iY > height_reg3 & iX>10'd18 & iX<10'd24;
assign
c4=iY > height_reg4 & iX>10'd24 & iX<10'd30;
assign
c5=iY > height_reg5 & iX>10'd30 & iX<10'd36;
assign
c6=iY > height_reg6 & iX>10'd36 & iX<10'd42;
assign
c7=iY > height_reg7 & iX>10'd42 & iX<10'd48;
assign
c8=iY > height_reg8 & iX>10'd48 & iX<10'd54;
assign
c9=iY > height_reg9 & iX>10'd54 & iX<10'd60;
assign
c10=iY > height_reg10 & iX>10'd60 & iX<10'd66;
assign
c11=iY > height_reg11 & iX>10'd66 & iX<10'd72;
assign
c12=iY > height_reg12 & iX>10'd72 & iX<10'd78;
assign
c13=iY > height_reg13 & iX>10'd78 & iX<10'd84;
assign
c14=iY > height_reg14 & iX>10'd84 & iX<10'd90;
assign
c15=iY > height_reg15 & iX>10'd90 & iX<10'd96;
assign
c16=iY > height_reg16 & iX>10'd96 & iX<10'd102;
assign
c17=iY > height_reg17 & iX>10'd102 & iX<10'd108;
assign
c18=iY > height_reg18 & iX>10'd108 & iX<10'd114;
assign
c19=iY > height_reg19 & iX>10'd114 & iX<10'd120;
assign
c20=iY > height_reg20 & iX>10'd120 & iX<10'd126;
assign
c21=iY > height_reg21 & iX>10'd126 & iX<10'd132;
assign
c22=iY > height_reg22 & iX>10'd132 & iX<10'd138;
assign
c23=iY > height_reg23 & iX>10'd138 & iX<10'd144;
assign
c24=iY > height_reg24 & iX>10'd144 & iX<10'd150;
assign
c25=iY > height_reg25 & iX>10'd150 & iX<10'd156;
assign
c26=iY > height_reg26 & iX>10'd156 & iX<10'd162;
assign
c27=iY > height_reg27 & iX>10'd162 & iX<10'd168;
assign
c28=iY > height_reg28 & iX>10'd168 & iX<10'd174;
assign
c29=iY > height_reg29 & iX>10'd174 & iX<10'd180;
assign
c30=iY > height_reg30 & iX>10'd180 & iX<10'd186;
assign
c31=iY > height_reg31 & iX>10'd186 & iX<10'd192;
assign
c32=iY > height_reg32 & iX>10'd192 & iX<10'd198;
assign
c33=iY > height_reg33 & iX>10'd198 & iX<10'd204;
assign
c34=iY > height_reg34 & iX>10'd204 & iX<10'd210;
assign
c35=iY > height_reg35 & iX>10'd210 & iX<10'd216;
assign
c36=iY > height_reg36 & iX>10'd216 & iX<10'd222;
assign
c37=iY > height_reg37 & iX>10'd222 & iX<10'd228;
assign
c38=iY > height_reg38 & iX>10'd228 & iX<10'd234;
assign
c39=iY > height_reg39 & iX>10'd234 & iX<10'd240;
assign
c40=iY > height_reg40 & iX>10'd240 & iX<10'd246;
assign
c41=iY > height_reg41 & iX>10'd246 & iX<10'd252;
assign
c42=iY > height_reg42 & iX>10'd252 & iX<10'd258;
assign
c43=iY > height_reg43 & iX>10'd258 & iX<10'd264;
assign
c44=iY > height_reg44 & iX>10'd264 & iX<10'd270;
assign
c45=iY > height_reg45 & iX>10'd270 & iX<10'd276;
assign
c46=iY > height_reg46 & iX>10'd276 & iX<10'd282;
assign
c47=iY > height_reg47 & iX>10'd282 & iX<10'd288;
assign
c48=iY > height_reg48 & iX>10'd288 & iX<10'd294;
assign
c49=iY > height_reg49 & iX>10'd294 & iX<10'd300;
assign
c50=iY > height_reg50 & iX>10'd300 & iX<10'd306;
assign
c51=iY > height_reg51 & iX>10'd306 & iX<10'd312;
assign
c52=iY > height_reg52 & iX>10'd312 & iX<10'd318;
assign
c53=iY > height_reg53 & iX>10'd318 & iX<10'd324;
assign
c54=iY > height_reg54 & iX>10'd324 & iX<10'd330;
assign
c55=iY > height_reg55 & iX>10'd330 & iX<10'd336;
assign
c56=iY > height_reg56 & iX>10'd336 & iX<10'd342;
assign
c57=iY > height_reg57 & iX>10'd342 & iX<10'd348;
assign
c58=iY > height_reg58 & iX>10'd348 & iX<10'd354;
assign
c59=iY > height_reg59 & iX>10'd354 & iX<10'd360;
assign
c60=iY > height_reg60 & iX>10'd360 & iX<10'd366;
assign
c61=iY > height_reg61 & iX>10'd366 & iX<10'd372;
assign
c62=iY > height_reg62 & iX>10'd372 & iX<10'd378;
assign
c63=iY > height_reg63 & iX>10'd378 & iX<10'd384;
assign
c64=iY > height_reg64 & iX>10'd384 & iX<10'd390;
assign
c65=iY > height_reg65 & iX>10'd390 & iX<10'd396;
assign
c66=iY > height_reg66 & iX>10'd396 & iX<10'd402;
assign
c67=iY > height_reg67 & iX>10'd402 & iX<10'd408;
assign
c68=iY > height_reg68 & iX>10'd408 & iX<10'd414;
assign
c69=iY > height_reg69 & iX>10'd414 & iX<10'd420;
assign
c70=iY > height_reg70 & iX>10'd420 & iX<10'd426;
assign
c71=iY > height_reg71 & iX>10'd426 & iX<10'd432;
assign
c72=iY > height_reg72 & iX>10'd432 & iX<10'd438;
assign
c73=iY > height_reg73 & iX>10'd438 & iX<10'd444;
assign
c74=iY > height_reg74 & iX>10'd444 & iX<10'd450;
assign
c75=iY > height_reg75 & iX>10'd450 & iX<10'd456;
assign
c76=iY > height_reg76 & iX>10'd456 & iX<10'd462;
assign
c77=iY > height_reg77 & iX>10'd462 & iX<10'd468;
assign
c78=iY > height_reg78 & iX>10'd468 & iX<10'd474;
assign
c79=iY > height_reg79 & iX>10'd474 & iX<10'd480;
assign
c80=iY > height_reg80 & iX>10'd480 & iX<10'd486;
assign
c81=iY > height_reg81 & iX>10'd486 & iX<10'd492;
assign
c82=iY > height_reg82 & iX>10'd492 & iX<10'd498;
assign
c83=iY > height_reg83 & iX>10'd498 & iX<10'd504;
assign
c84=iY > height_reg84 & iX>10'd504 & iX<10'd510;
assign
c85=iY > height_reg85 & iX>10'd510 & iX<10'd516;
assign
c86=iY > height_reg86 & iX>10'd516 & iX<10'd522;
assign
c87=iY > height_reg87 & iX>10'd522 & iX<10'd528;
assign
c88=iY > height_reg88 & iX>10'd528 & iX<10'd534;
assign
c89=iY > height_reg89 & iX>10'd534 & iX<10'd540;
assign
c90=iY > height_reg90 & iX>10'd540 & iX<10'd546;
assign
c91=iY > height_reg91 & iX>10'd546 & iX<10'd552;
assign
c92=iY > height_reg92 & iX>10'd552 & iX<10'd558;
assign
c93=iY > height_reg93 & iX>10'd558 & iX<10'd564;
assign
c94=iY > height_reg94 & iX>10'd564 & iX<10'd570;
assign
c95=iY > height_reg95 & iX>10'd570 & iX<10'd576;
assign
c96=iY > height_reg96 & iX>10'd576 & iX<10'd582;
assign
c97=iY > height_reg97 & iX>10'd582 & iX<10'd588;
assign
c98=iY > height_reg98 & iX>10'd588 & iX<10'd594;
assign
c99=iY > height_reg99 & iX>10'd594 & iX<10'd600;
//eye
tracking
assign
eye1= iY >10'd40-height_reg10[4:0] & iY <10'd40+eyeheight+height_reg10[4:0]
& iX >10'd140-height_reg10[4:0] & iX
<10'd140+eyewidth+height_reg10[4:0];
assign
eye2= iY >10'd40-height_reg20[4:0] & iY
<10'd40+eyeheight+height_reg20[4:0] & iX >10'd480-height_reg20[4:0]
& iX <10'd480+eyewidth+height_reg20[4:0];
always
@ (posedge CLK) begin
if(RST) begin //reset
switchColor<=0;
draw_state<=init;
height_reg0<=0;
height_reg1<=0;
height_reg2<=0;
height_reg3<=0;
height_reg4<=0;
height_reg5<=0;
height_reg6<=0;
height_reg7<=0;
height_reg8<=0;
height_reg9<=0;
height_reg10<=0;
height_reg11<=0;
height_reg12<=0;
height_reg13<=0;
height_reg14<=0;
height_reg15<=0;
height_reg16<=0;
height_reg17<=0;
height_reg18<=0;
height_reg19<=0;
height_reg20<=0;
height_reg21<=0;
height_reg22<=0;
height_reg23<=0;
height_reg24<=0;
height_reg25<=0;
height_reg26<=0;
height_reg27<=0;
height_reg28<=0;
height_reg29<=0;
height_reg30<=0;
height_reg31<=0;
height_reg32<=0;
height_reg33<=0;
height_reg34<=0;
height_reg35<=0;
height_reg36<=0;
height_reg37<=0;
height_reg38<=0;
height_reg39<=0;
height_reg40<=0;
height_reg41<=0;
height_reg42<=0;
height_reg43<=0;
height_reg44<=0;
height_reg45<=0;
height_reg46<=0;
height_reg47<=0;
height_reg48<=0;
height_reg49<=0;
height_reg50<=0;
height_reg51<=0;
height_reg52<=0;
height_reg53<=0;
height_reg54<=0;
height_reg55<=0;
height_reg56<=0;
height_reg57<=0;
height_reg58<=0;
height_reg59<=0;
height_reg60<=0;
height_reg61<=0;
height_reg62<=0;
height_reg63<=0;
height_reg64<=0;
height_reg65<=0;
height_reg66<=0;
height_reg67<=0;
height_reg68<=0;
height_reg69<=0;
height_reg70<=0;
height_reg71<=0;
height_reg72<=0;
height_reg73<=0;
height_reg74<=0;
height_reg75<=0;
height_reg76<=0;
height_reg77<=0;
height_reg78<=0;
height_reg79<=0;
height_reg80<=0;
height_reg81<=0;
height_reg82<=0;
height_reg83<=0;
height_reg84<=0;
height_reg85<=0;
height_reg86<=0;
height_reg87<=0;
height_reg88<=0;
height_reg89<=0;
height_reg90<=0;
height_reg91<=0;
height_reg92<=0;
height_reg93<=0;
height_reg94<=0;
height_reg95<=0;
height_reg96<=0;
height_reg97<=0;
height_reg98<=0;
height_reg99<=0;
end
else begin
sampleCount
<= sampleCount + 24'd1;
case(draw_state)
init:
begin
if(sampleCount
> period[13:0])begin
sampleCount
<= 24'd0;
sampleAudio
<= audIn;
sampleBass
<= bass;
sampleCymbal
<= cymbal;
sampleVoice
<= voice;
end
case(sigSel[1:0])
2'd0:
height_reg0 <= 10'd479-iHeight;
2'd1:
height_reg0 <= 10'd479-bassH;
2'd2:
height_reg0 <= 10'd479-cymbalH;
2'd3:
height_reg0 <= 10'd479-voiceH;
endcase
height_reg1
<= height_reg0;
height_reg2
<= height_reg1;
height_reg3
<= height_reg2;
height_reg4
<= height_reg3;
height_reg5
<= height_reg4;
height_reg6
<= height_reg5;
height_reg7
<= height_reg6;
height_reg8
<= height_reg7;
height_reg9
<= height_reg8;
height_reg10
<= height_reg9;
height_reg11
<= height_reg10;
height_reg12
<= height_reg11;
height_reg13
<= height_reg12;
height_reg14
<= height_reg13;
height_reg15
<= height_reg14;
height_reg16
<= height_reg15;
height_reg17
<= height_reg16;
height_reg18
<= height_reg17;
height_reg19
<= height_reg18;
height_reg20
<= height_reg19;
height_reg21
<= height_reg20;
height_reg22
<= height_reg21;
height_reg23
<= height_reg22;
height_reg24
<= height_reg23;
height_reg25
<= height_reg24;
height_reg26
<= height_reg25;
height_reg27
<= height_reg26;
height_reg28
<= height_reg27;
height_reg29
<= height_reg28;
height_reg30
<= height_reg29;
height_reg31
<= height_reg30;
height_reg32
<= height_reg31;
height_reg33
<= height_reg32;
height_reg34
<= height_reg33;
height_reg35
<= height_reg34;
height_reg36
<= height_reg35;
height_reg37
<= height_reg36;
height_reg38
<= height_reg37;
height_reg39
<= height_reg38;
height_reg40
<= height_reg39;
height_reg41
<= height_reg40;
height_reg42
<= height_reg41;
height_reg43
<= height_reg42;
height_reg44
<= height_reg43;
height_reg45
<= height_reg44;
height_reg46
<= height_reg45;
height_reg47
<= height_reg46;
height_reg48
<= height_reg47;
height_reg49
<= height_reg48;
height_reg50
<= height_reg49;
height_reg51
<= height_reg50;
height_reg52
<= height_reg51;
height_reg53
<= height_reg52;
height_reg54
<= height_reg53;
height_reg55
<= height_reg54;
height_reg56
<= height_reg55;
height_reg57
<= height_reg56;
height_reg58
<= height_reg57;
height_reg59
<= height_reg58;
height_reg60
<= height_reg59;
height_reg61
<= height_reg60;
height_reg62
<= height_reg61;
height_reg63
<= height_reg62;
height_reg64
<= height_reg63;
height_reg65
<= height_reg64;
height_reg66
<= height_reg65;
height_reg67
<= height_reg66;
height_reg68
<= height_reg67;
height_reg69
<= height_reg68;
height_reg70
<= height_reg69;
height_reg71
<= height_reg70;
height_reg72
<= height_reg71;
height_reg73
<= height_reg72;
height_reg74
<= height_reg73;
height_reg75
<= height_reg74;
height_reg76
<= height_reg75;
height_reg77
<= height_reg76;
height_reg78
<= height_reg77;
height_reg79
<= height_reg78;
height_reg80
<= height_reg79;
height_reg81
<= height_reg80;
height_reg82
<= height_reg81;
height_reg83
<= height_reg82;
height_reg84
<= height_reg83;
height_reg85
<= height_reg84;
height_reg86
<= height_reg85;
height_reg87
<= height_reg86;
height_reg88
<= height_reg87;
height_reg89
<= height_reg88;
height_reg90
<= height_reg89;
height_reg91
<= height_reg90;
height_reg92
<= height_reg91;
height_reg93
<= height_reg92;
height_reg94
<= height_reg93;
height_reg95
<= height_reg94;
height_reg96
<= height_reg95;
height_reg97
<= height_reg96;
height_reg98
<= height_reg97;
height_reg99
<= height_reg98;
draw_state<=color;
end
color:
begin
if((c0|c1|c2|c3|c4|c5|c6|c7|c8|c9|c10|c11|c12|c13|c14|c15|c16|c17|c18|c19|c20|c21|c22|c23|c24|c25|c26|c27|c28|c29|c30|c31|c32|c33|c34|c35|c36|c37|c38|c39|c40|c41|c42|c43|c44|c45|c46|c47|c48|c49|c50|c51|c52|c53|c54|c55|c56|c57|c58|c59|c60|c61|c62|c63|c64|c65|c66|c67|c68|c69|c70|c71|c72|c73|c74|c75|c76|c77|c78|c79|c80|c81|c82|c83|c84|c85|c86|c87|c88|c89|c90|c91|c92|c93|c94|c95|c96|c97|c98|c99)
& ~(iY%10 ==0) | eye1 | eye2) begin
if
(sigSel[4:2]==3'd0) begin
reg_R<=red;//10'h0;
reg_G<=green;//10'h0;
reg_B<=blue;//10'hfff;
end
else if (sigSel[4:2]==3'd1) begin
reg_R
<= sampleAudio[14:5];
reg_G
<= ~sampleAudio[12:3];
reg_B
<= sampleAudio[9:0];
end
else if (sigSel[4:2]==3'd2) begin
reg_R
<= sampleBass[14:5];
reg_G
<= ~sampleBass[12:3];
reg_B
<= sampleBass[9:0];
end
else if (sigSel[4:2]==3'd3) begin
reg_R
<= sampleCymbal[14:5];
reg_G
<= ~sampleCymbal[12:3];
reg_B
<= sampleCymbal[9:0];
end
else if (sigSel[4:2]==3'd4) begin
reg_R
<= sampleVoice[14:5];
reg_G
<= ~sampleVoice[12:3];
reg_B
<= sampleVoice[9:0];
end
else begin
reg_R<=red;//10'h0;
reg_G<=green;//10'h0;
reg_B<=blue;//10'hfff;
end
if(eye1)
begin
if
(sigSel[4:2]==3'd0)begin
reg_R<=red;
reg_G<=green;
reg_B<=~blue;
end
else if (sigSel[4:2]==3'd5) begin
reg_R<=~sampleBass[14:5];
reg_G<=~sampleCymbal[14:5];
reg_B<=~sampleVoice[14:5];
end
else if (sigSel[4:2]==3'd6) begin
reg_R<=~sampleCymbal[14:5];
reg_G<=~sampleVoice[14:5];
reg_B<=~sampleBass[14:5];
end
else if (sigSel[4:2]==3'd7) begin
reg_R<=~sampleVoice[14:5];
reg_G<=~sampleBass[14:5];
reg_B<=~sampleCymbal[14:5];
end
end
if(eye2)
begin
if
(sigSel[4:2]==3'd0)begin
reg_R<=red;
reg_G<=~green;
reg_B<=blue;
end
else if (sigSel[4:2]==3'd5) begin
reg_R<=~bass[14:5];
reg_G<=~cymbal[14:5];
reg_B<=~voice[14:5];
end
else if (sigSel[4:2]==3'd6) begin
reg_R<=~cymbal[14:5];
reg_G<=~voice[14:5];
reg_B<=~bass[14:5];
end
else if (sigSel[4:2]==3'd7) begin
reg_R<=~voice[14:5];
reg_G<=~bass[14:5];
reg_B<=~cymbal[14:5];
end
end
end
else begin // if not conditions are met
reg_R<=10'h0;
reg_G<=10'h0;
reg_B<=10'h0;
end
if(vs_sig)
//finished drawing
draw_state<=init;
end
endcase
end //VGA sync
end
//always
assign
state=draw_state;
reg
vs_state;
reg
vs_sig;
always
@ (posedge CLK) begin //generate a one cycle pulse on each v sync,signals a
fully drawn screen
if(RST) begin
vs_state<=0;
end
else begin
case(vs_state)
0:
begin
vs_sig<=0;
if(~iVGA_VS)
begin
vs_sig<=1;
vs_state<=1;
end
end
1:
begin
vs_sig<=0;
if(iVGA_VS)
vs_state<=0;
end
endcase
end
end
assign
oR= reg_R;
assign
oG= reg_G;
assign
oB= reg_B;
endmodule
///////////////////////////////////////////////////////////////////
//////////////absolute
values//////////////////////////////////////
///////////////////////////////////////////////////////////////////
module
abs(out, in, dk_const, clk);
output reg signed [15:0]
out ;
input wire signed [15:0]
in ;
input wire [3:0]
dk_const ;
input wire clk;
wire signed [17:0] new_out ;
//take absolute value
and reduce amplitude
assign new_out =
(in[15]?-in:in)>>dk_const;//out - (out>>>dk_const) +
((in[15]?-in:in)>>>dk_const) ;
always @(posedge clk)
begin
out <= new_out ;
end
endmodule
///////////////////////////////////////////////////////////////////
////////////
highest order bit find ///////////////////////////////
///////////////////////////////////////////////////////////////////
module
firstHbit(in,out,CLK);
input
CLK;
input
[9:0] in;
output
[9:0] out;
reg
[9:0] out_reg;
always
@ (posedge CLK) begin
if(in[9])
out_reg<=10'd479;
else if(in[8])
out_reg<=10'd360;
else if(in[7])
out_reg<=10'd320;
else if(in[6])
out_reg<=10'd280;
else if(in[5])
out_reg<=10'd240;
else if(in[4])
out_reg<=10'd200;
else if(in[3])
out_reg<=10'd160;
else if(in[2])
out_reg<=10'd120;
else if(in[1])
out_reg<=10'd80;
else if(in[0])
out_reg<=10'd40;
else
out_reg<=10'd0;
end
//always
assign
out=out_reg;
endmodule
///////////////////////////////////////////////////////////////////
////
signed mult of 2.16 format 2'comp ////////////////////////////
///////////////////////////////////////////////////////////////////
module
signed_mult (out, a, b);
output [17:0] out;
input signed [17:0] a;
input signed [17:0] b;
wire signed [17:0] out;
wire signed [35:0] mult_out;
assign mult_out = a * b;
//assign out =
mult_out[33:17];
assign out =
{mult_out[35], mult_out[32:16]};
endmodule
///////////////////////////////////////////////////////////////////
///
Fourth order IIR filter ///////////////////////////////////////
///////////////////////////////////////////////////////////////////
module
IIR4_18bit_fixed (audio_out, audio_in,
scale,
b1,
b2, b3, b4, b5,
a2,
a3, a4, a5,
state_clk,
lr_clk, reset) ;
//
The filter is a "Direct Form II Transposed"
//
// a(1)*y(n) = b(1)*x(n) + b(2)*x(n-1) + ... +
b(nb+1)*x(n-nb)
// - a(2)*y(n-1) - ... -
a(na+1)*y(n-na)
//
// If a(1) is not equal to 1, FILTER
normalizes the filter
// coefficients by a(1).
//
//
one audio sample, 16 bit, 2's complement
output
reg signed [15:0] audio_out ;
//
one audio sample, 16 bit, 2's complement
input
wire signed [15:0] audio_in ;
//
shift factor for output
input
wire [2:0] scale ;
//
filter coefficients
input
wire signed [17:0] b1, b2, b3, b4, b5, a2, a3, a4, a5 ;
input
wire state_clk, lr_clk, reset ;
///
filter vars //////////////////////////////////////////////////
wire
signed [17:0] f1_mac_new, f1_coeff_x_value ;
reg
signed [17:0] f1_coeff, f1_mac_old, f1_value ;
//
input to filter
reg
signed [17:0] x_n ;
//
input history x(n-1), x(n-2)
reg
signed [17:0] x_n1, x_n2, x_n3, x_n4 ;
//
output history: y_n is the new filter output, BUT it is
//
immediately stored in f1_y_n1 for the next loop through
//
the filter state machine
reg
signed [17:0] f1_y_n1, f1_y_n2, f1_y_n3, f1_y_n4 ;
//
MAC operation
signed_mult
f1_c_x_v (f1_coeff_x_value, f1_coeff, f1_value);
assign
f1_mac_new = f1_mac_old + f1_coeff_x_value ;
//
state variable
reg
[3:0] state ;
//oneshot
gen to sync to audio clock
reg
last_clk ;
///////////////////////////////////////////////////////////////////
//Run
the filter state machine FAST so that it completes in one
//audio
cycle
always
@ (posedge state_clk)
begin
if (reset)
begin
state
<= 4'd15 ; //turn off the state machine
end
else begin
case
(state)
1:
begin
//
set up b1*x(n)
f1_mac_old
<= 18'd0 ;
f1_coeff
<= b1 ;
f1_value
<= {audio_in, 2'b0} ;
//register
input
x_n
<= {audio_in, 2'b0} ;
//
next state
state
<= 4'd2;
end
2:
begin
//
set up b2*x(n-1)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= b2 ;
f1_value
<= x_n1 ;
//
next state
state
<= 4'd3;
end
3:
begin
//
set up b3*x(n-2)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= b3 ;
f1_value
<= x_n2 ;
//
next state
state
<= 4'd4;
end
4:
begin
//
set up b4*x(n-3)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= b4 ;
f1_value
<= x_n3 ;
//
next state
state
<= 4'd5;
end
5:
begin
//
set up b5*x(n-4)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= b5 ;
f1_value
<= x_n4 ;
//
next state
state
<= 4'd6;
end
6:
begin
//
set up -a2*y(n-1)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= a2 ;
f1_value
<= f1_y_n1 ;
//next
state
state
<= 4'd7;
end
7:
begin
//
set up -a3*y(n-2)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= a3 ;
f1_value
<= f1_y_n2 ;
//next
state
state
<= 4'd8;
end
8:
begin
//
set up -a4*y(n-3)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= a4 ;
f1_value
<= f1_y_n3 ;
//next
state
state
<= 4'd9;
end
9:
begin
//
set up -a5*y(n-4)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= a5 ;
f1_value
<= f1_y_n4 ;
//next
state
state
<= 4'd10;
end
10:
begin
//
get the output
//
and put it in the LAST output var
//
for the next pass thru the state machine
//mult
by four because of coeff scaling
//
to prevent overflow
f1_y_n1
<= f1_mac_new<<scale ;
audio_out
<= f1_y_n1[17:2] ;
//
update output history
f1_y_n2
<= f1_y_n1 ;
f1_y_n3
<= f1_y_n2 ;
f1_y_n4
<= f1_y_n3 ;
//
update input history
x_n1
<= x_n ;
x_n2
<= x_n1 ;
x_n3
<= x_n2 ;
x_n4
<= x_n3 ;
//next
state
state
<= 4'd15;
end
15:
begin
//
wait for the audio clock and one-shot it
if
(lr_clk && last_clk==1)
begin
state
<= 4'd1 ;
last_clk
<= 1'h0 ;
end
//
reset the one-shot memory
else
if (~lr_clk && last_clk==0)
begin
last_clk
<= 1'h1 ;
end
end
default:
begin
//
default state is end state
state
<= 4'd15 ;
end
endcase
end
end
endmodule
///////////////////////////////////////////////////////////////////
////
signed mult of 3.24 format 2'comp/////////////////////////////
///////////////////////////////////////////////////////////////////
module
signed_mult27 (out, a, b);
output [26:0] out;
input signed [26:0] a;
input signed [26:0] b;
wire signed [26:0] out;
wire signed [53:0] mult_out;
assign mult_out = a * b;
assign out =
{mult_out[53], mult_out[50:24]};
endmodule
///////////////////////////////////////////////////////////////////
///
Fourth order IIR filter ///////////////////////////////////////
///////////////////////////////////////////////////////////////////
module
IIR4_27bit (audio_out, audio_in,
scale,
b1,
b2, b3, b4, b5,
a2,
a3, a4, a5,
state_clk,
lr_clk, reset) ;
//
The filter is a "Direct Form II Transposed"
//
// a(1)*y(n) = b(1)*x(n) + b(2)*x(n-1) + ... +
b(nb+1)*x(n-nb)
// - a(2)*y(n-1) - ... -
a(na+1)*y(n-na)
//
// If a(1) is not equal to 1, FILTER
normalizes the filter
// coefficients by a(1).
//
//
one audio sample, 16 bit, 2's complement
output
reg signed [15:0] audio_out ;
//
one audio sample, 16 bit, 2's complement
input
wire signed [15:0] audio_in ;
//
shift factor for output
input
wire [2:0] scale ;
//
filter coefficients
input
wire signed [26:0] b1, b2, b3, b4, b5, a2, a3, a4, a5 ;
input
wire state_clk, lr_clk, reset ;
///
filter vars //////////////////////////////////////////////////
wire
signed [26:0] f1_mac_new, f1_coeff_x_value ;
reg
signed [26:0] f1_coeff, f1_mac_old, f1_value ;
//
input to filter
reg
signed [26:0] x_n ;
//
input history x(n-1), x(n-2)
reg
signed [26:0] x_n1, x_n2, x_n3, x_n4 ;
//
output history: y_n is the new filter output, BUT it is
//
immediately stored in f1_y_n1 for the next loop through
//
the filter state machine
reg
signed [26:0] f1_y_n1, f1_y_n2, f1_y_n3, f1_y_n4 ;
//
MAC operation
signed_mult27
f1_c_x_v (f1_coeff_x_value, f1_coeff, f1_value);
assign
f1_mac_new = f1_mac_old + f1_coeff_x_value ;
//
state variable
reg
[3:0] state ;
//oneshot
gen to sync to audio clock
reg
last_clk ;
///////////////////////////////////////////////////////////////////
//Run
the filter state machine FAST so that it completes in one
//audio
cycle
always
@ (posedge state_clk)
begin
if (reset)
begin
state
<= 4'd15 ; //turn off the state machine
end
else begin
case
(state)
1:
begin
//
set up b1*x(n)
f1_mac_old
<= 27'd0 ;
f1_coeff
<= b1 ;
f1_value
<= {audio_in, 11'b0} ;
//register
input
x_n
<= {audio_in, 11'b0} ;
//
next state
state
<= 4'd2;
end
2:
begin
//
set up b2*x(n-1)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= b2 ;
f1_value
<= x_n1 ;
//
next state
state
<= 4'd3;
end
3:
begin
//
set up b3*x(n-2)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= b3 ;
f1_value
<= x_n2 ;
//
next state
state
<= 4'd4;
end
4:
begin
//
set up b4*x(n-3)
f1_mac_old <=
f1_mac_new ;
f1_coeff
<= b4 ;
f1_value
<= x_n3 ;
//
next state
state
<= 4'd5;
end
5:
begin
//
set up b5*x(n-4)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= b5 ;
f1_value
<= x_n4 ;
//
next state
state <= 4'd6;
end
6:
begin
//
set up -a2*y(n-1)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= a2 ;
f1_value
<= f1_y_n1 ;
//next
state
state
<= 4'd7;
end
7:
begin
//
set up -a3*y(n-2)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= a3 ;
f1_value
<= f1_y_n2 ;
//next
state
state
<= 4'd8;
end
8:
begin
//
set up -a4*y(n-3)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= a4 ;
f1_value
<= f1_y_n3 ;
//next
state
state
<= 4'd9;
end
9:
begin
//
set up -a5*y(n-4)
f1_mac_old
<= f1_mac_new ;
f1_coeff
<= a5 ;
f1_value
<= f1_y_n4 ;
//next
state
state
<= 4'd10;
end
10:
begin
//
get the output
//
and put it in the LAST output var
//
for the next pass thru the state machine
//mult
by four because of coeff scaling
//
to prevent overflow
f1_y_n1
<= f1_mac_new<<scale ;
audio_out
<= f1_y_n1[26:11] ;
//
update output history
f1_y_n2
<= f1_y_n1 ;
f1_y_n3
<= f1_y_n2 ;
f1_y_n4
<= f1_y_n3 ;
//
update input history
x_n1
<= x_n ;
x_n2
<= x_n1 ;
x_n3
<= x_n2 ;
x_n4
<= x_n3 ;
//next
state
state
<= 4'd15;
end
15:
begin
//
wait for the audio clock and one-shot it
if
(lr_clk && last_clk==1)
begin
state
<= 4'd1 ;
last_clk
<= 1'h0 ;
end
//
reset the one-shot memory
else
if (~lr_clk && last_clk==0)
begin
last_clk
<= 1'h1 ;
end
end
default:
begin
//
default state is end state
state
<= 4'd15 ;
end
endcase
end
end
endmodule
///////////////////////////////////////////////////////////////////
/////////////////////
Pixel Value Controller //////////////////////
///////////////////////////////////////////////////////////////////
module
pixelController(reset, schemeReset, CLK, CLK27, AUDCLK, VGA_VS, VGA_HS, audIn,
periodIn, red, green, blue);
//inputs
input
reset, VGA_VS, VGA_HS, CLK, CLK27, AUDCLK;
input
[7:0] schemeReset;
input
signed [15:0] audIn;
input
[31:0] periodIn;
//registers
reg
[1:0] wtPrd;
reg
[31:0] realPeriod;
reg
[7:0] schemeCycle;
reg
[31:0] schemeCount;
//outputs
output
[9:0] red, green, blue;
//output
[31:0] periodOut;
//wires
wire
[9:0] redValue, greenValue, blueValue;
//wire
[31:0] period;
//waveform
period calculator
//periodCalc
calcUnit1(CLK, CLK27, AUDCLK, clk1000, audIn, period);
//pixel
variation unit
pixelVar
unit1(reset, VGA_VS, CLK, schemeCycle, wtPrd, realPeriod, redValue, greenValue,
blueValue);
//scheme
logic
always
@ (posedge CLK) begin
if (reset) begin
schemeCount
<= 32'd0;
schemeCycle
<= schemeReset;
end else begin
//
scheme cycler
schemeCount
<= schemeCount + 32'd1;
if(schemeCount
> (periodIn<<4)) begin//32'd90000000)begin
schemeCount
<= 32'd0;
//schemeSubCount
<= schemeSubCount + 20'd1;
schemeCycle
<= schemeCycle + 8'd1;
if
(schemeCycle > 8'd254) begin//(schemeCycle > 8'd255) begin
schemeCycle
<= 8'd0;
wtPrd
<= wtPrd + 2'd1;
if
(wtPrd == 2'd3) begin
wtPrd
<= 2'd0;
schemeCycle
<= schemeCycle + 8'd1;
end
end
end
end
realPeriod <=
(periodIn>>5);
end
//assign
outputs
assign
red = redValue;
assign
green = greenValue;
assign
blue = blueValue;
//assign
periodOut = period;
endmodule
///////////////////////////////////////////////////////////////////
/////////////
CIC N=2 M=1 filter //////////////////////////////////
///////////////////////////////////////////////////////////////////
module
CIC_N2_M1_16bit_fixed (audio_out, rf_in,
rf_clk,
lr_clk, reset) ;
//
The filter is a
//
double integrator/comb CIC filter
//
//
one audio sample, 16 bit, 2's complement
output
reg signed [15:0] audio_out ;
input
signed [15:0] rf_in ;
input
wire rf_clk, lr_clk, reset ;
reg
signed [39:0] integrator1, comb1 ; //[39:0]
reg
signed [39:0] integrator2, comb2, temp_int2 ;
wire
signed [39:0] running_sum1, running_sum2
;
always
@(posedge rf_clk)
begin
if (reset)
begin
integrator1
<= 40'd0 ;
integrator2
<= 40'd0 ;
end
else
begin
integrator1
<= integrator1 + { {24{rf_in[15]}}, rf_in} ;
integrator2
<= integrator2 + integrator1 ;
end
end
always
@(posedge lr_clk)
begin
temp_int2 <=
integrator2 ;
comb1 <= temp_int2 ;
comb2 <= running_sum1
;
audio_out <= running_sum2[35:20];
end
assign
running_sum1 = temp_int2 - comb1 ;
assign
running_sum2 = running_sum1 - comb2 ;
endmodule
///////////////////////////////////////////////////////////////////
//////////////////////
Pixel Color Variation Unit /////////////////
///////////////////////////////////////////////////////////////////
module
pixelVar(reset, VGA_VS, CLK, scheme, wtPer, period, red, green, blue);
//inputs
input
CLK, reset, VGA_VS;
input
[1:0] wtPer;
input
[8:0] scheme;
input
[31:0] period;
//registers
reg
reverse; // reverse the order in which operation is done
reg
stat; //stationay second color
reg
alt; //second color alternates
reg
sync; //synchronize with VGA_VS or not
reg
[1:0] thirdVal;
reg
[2:0] mode;
reg
[2:0] maxCount;
reg
[15:0] counter;
reg
[31:0] countMax;
reg
[9:0] redVal, blueVal, greenVal;
//outputs
output
[9:0] red, green, blue;
always
@ (posedge CLK) begin
sync <= scheme[8];
if (reset) begin//if
system is reset
redVal
<= 10'd0;
greenVal
<= 10'd0;
blueVal
<= 10'd0;
counter
<= 16'd0;
end else if (~VGA_VS)
begin
mode
<= scheme[7:5];
reverse
<= scheme[4];
thirdVal
<= scheme[3:2];
stat
<= scheme[1];
alt
<= scheme[0];
counter
<= counter + 16'd1;//increment count
//set
count max - different wait periods to cycle colors
case(wtPer)
2'd0:
countMax <= period<<3; // 8x bass beat (2x whole note)
2'd1:
countMax <= period<<2; // 4x bass beat (whole note)
2'd2:
countMax <= period<<1; // 2x bass beat (half note)
2'd3:
countMax <= period;//bass beat (quarter note)
endcase
//select
color shifting mode
case(mode)
3'd0:
begin // red up, green down (reverse is direction switch)
//different
wait period to cycle colors
if
(counter > countMax) begin
maxCount
<= maxCount + 3'd1;
counter
<= 16'd0;
//red
value
if(reverse)
begin
if
(redVal < 10'd1020) begin
redVal
<= redVal + 10'd10;
end
else begin
redVal
<= 10'd0;
end
end
else begin
if
(redVal > 10'd0) begin
redVal
<= redVal - 10'd10;
end
else begin
redVal
<= 10'd1020;
end
end
//green
value
if
(~stat) begin //stationary second color
if
(reverse) begin
if
(greenVal > 10'd0) begin
greenVal
<= greenVal - 10'd10;
end
else begin
greenVal
<= 10'd1020;
end
end
else begin
if
(greenVal < 10'd1020) begin
greenVal
<= greenVal + 10'd10;
end
else begin
greenVal
<= 10'd0;
end
end
if
(alt && maxCount>3) begin //alternate third color
maxCount
<= 3'd0;
if
(blueVal==10'd1000) begin //reset third color at 1000
blueVal
<= 10'd0;
end
else begin
blueVal
<= blueVal + 10'd200;
end
end
else begin//set third color to constant value
case(thirdVal)
2'd0:
blueVal <= 10'd0;
2'd1:
blueVal <= 10'd250;
2'd2:
blueVal <= 10'd500;
2'd3:
blueVal <= 10'd750;
endcase
end
end
else begin
if
(alt && maxCount>3) begin //alternate second color
maxCount
<= 3'd0;
if
(greenVal==10'd1000) begin //reset second color at 1000
greenVal
<= 10'd0;
end
else begin
greenVal
<= greenVal + 10'd200;
end
end
end
//stat check
end
//end count check
end
//end of this case
3'd1:
begin //blue up, red down (reverse is direction switch)
//different
wait period to cycle colors
if
(counter > countMax) begin
maxCount
<= maxCount + 3'd1;
counter
<= 16'd0;
//red
value
if(reverse)
begin
if
(blueVal < 10'd1020) begin
blueVal
<= blueVal + 10'd10;
end
else begin
blueVal
<= 10'd0;
end
end
else begin
if
(blueVal > 10'd0) begin
blueVal
<= blueVal - 10'd10;
end
else begin
blueVal
<= 10'd1020;
end
end
//green
value
if
(~stat) begin //stationary second color
if
(reverse) begin
if
(redVal > 10'd0) begin
redVal
<= redVal - 10'd10;
end
else begin
redVal
<= 10'd1020;
end
end
else begin
if
(redVal < 10'd1020) begin
redVal
<= redVal + 10'd10;
end
else begin
redVal
<= 10'd0;
end
end
if
(alt && maxCount>3) begin //alternate third color
maxCount
<= 3'd0;
if
(greenVal==10'd1000) begin //reset third color at 1000
greenVal
<= 10'd0;
end
else begin
greenVal
<= greenVal + 10'd200;
end
end
else begin//set third color to constant value
case(thirdVal)
2'd0:
greenVal <= 10'd0;
2'd1:
greenVal <= 10'd250;
2'd2:
greenVal <= 10'd500;
2'd3:
greenVal <= 10'd750;
endcase
end
end
else begin
if
(alt && maxCount>3) begin //alternate second color
maxCount
<= 3'd0;
if
(redVal==10'd1000) begin //reset second color at 1000
redVal
<= 10'd0;
end
else begin
redVal
<= redVal + 10'd200;
end
end
end
//stat check
end
//end count check
end//end
of this case
3'd2:
begin //green up, blue down (reverse is direction switch)
//different
wait period to cycle colors
if
(counter > countMax) begin
maxCount
<= maxCount + 3'd1;
counter
<= 16'd0;
//red
value
if(reverse)
begin
if
(greenVal < 10'd1020) begin
greenVal
<= greenVal + 10'd10;
end
else begin
greenVal
<= 10'd0;
end
end
else begin
if
(greenVal < 10'd1020) begin
greenVal
<= greenVal - 10'd10;
end
else begin
greenVal
<= 10'd1020;
end
end
//green
value
if
(~stat) begin //stationary second color
if
(reverse) begin
if
(blueVal > 10'd0) begin
blueVal
<= blueVal - 10'd10;
end
else begin
blueVal
<= 10'd1020;
end
end
else begin
if
(blueVal < 10'd1020) begin
blueVal
<= blueVal + 10'd10;
end
else begin
blueVal
<= 10'd0;
end
end
if
(alt && maxCount>3) begin //alternate third color
maxCount
<= 3'd0;
if
(redVal==10'd1000) begin //reset third color at 1000
redVal
<= 10'd0;
end
else begin
redVal
<= redVal + 10'd200;
end
end
else begin//set third color to constant value
case(thirdVal)
2'd0:
redVal <= 10'd0;
2'd1:
redVal <= 10'd250;
2'd2:
redVal <= 10'd500;
2'd3:
redVal <= 10'd750;
endcase
end
end
else begin
if
(alt && maxCount>3) begin //alternate second color
maxCount
<= 3'd0;
if
(blueVal==10'd1000) begin //reset second color at 1000
blueVal
<= 10'd0;
end
else begin
blueVal
<= blueVal + 10'd200;
end
end
end
//stat check
end
//end count check
end//end
of this case
3'd3:
begin //blue up, green down (reverse is direction switch)
//different
wait period to cycle colors
if
(counter > countMax) begin
maxCount
<= maxCount + 3'd1;
counter
<= 16'd0;
//red
value
if(reverse)
begin
if
(blueVal < 10'd1020) begin
blueVal
<= blueVal + 10'd10;
end
else begin
blueVal
<= 10'd0;
end
end
else begin
if
(blueVal > 10'd0) begin
blueVal
<= blueVal - 10'd10;
end
else begin
blueVal
<= 10'd1020;
end
end
//green
value
if
(~stat) begin //stationary second color
if
(reverse) begin
if
(greenVal > 10'd0) begin
greenVal
<= greenVal - 10'd10;
end
else begin
greenVal
<= 10'd1020;
end
end
else begin
if
(greenVal < 10'd1020) begin
greenVal
<= greenVal + 10'd10;
end
else begin
greenVal
<= 10'd0;
end
end
if
(alt && maxCount>3) begin //alternate third color
maxCount
<= 3'd0;
if
(redVal==10'd1000) begin //reset third color at 1000
redVal
<= 10'd0;
end
else begin
redVal
<= redVal + 10'd200;
end
end
else begin//set third color to constant value
case(thirdVal)
2'd0:
redVal <= 10'd0;
2'd1:
redVal <= 10'd250;
2'd2:
redVal <= 10'd500;
2'd3:
redVal <= 10'd750;
endcase
end
end
else begin
if
(alt && maxCount>3) begin //alternate second color
maxCount
<= 3'd0;
if
(greenVal==10'd1000) begin //reset second color at 1000
greenVal
<= 10'd0;
end
else begin
greenVal
<= greenVal + 10'd200;
end
end
end //stat check
end
//end count check
end//end
of this case
3'd4:
begin //green up, red down (reverse is direction switch)
//different
wait period to cycle colors
if
(counter > countMax) begin
maxCount
<= maxCount + 3'd1;
counter
<= 16'd0;
//red
value
if(reverse)
begin
if
(greenVal < 10'd1020) begin
greenVal
<= greenVal + 10'd10;
end
else begin
greenVal
<= 10'd0;
end
end
else begin
if
(greenVal > 10'd0) begin
greenVal
<= greenVal - 10'd10;
end
else begin
greenVal
<= 10'd1020;
end
end
//green
value
if
(~stat) begin //stationary second color
if
(reverse) begin
if
(redVal > 10'd0) begin
redVal
<= redVal - 10'd10;
end
else begin
redVal
<= 10'd1020;
end
end
else begin
if
(redVal < 10'd1020) begin
redVal
<= redVal + 10'd10;
end
else begin
redVal
<= 10'd0;
end
end
if
(alt && maxCount>3) begin //alternate third color
maxCount
<= 3'd0;
if
(blueVal==10'd1000) begin //reset third color at 1000
blueVal
<= 10'd0;
end
else begin
blueVal
<= blueVal + 10'd200;
end
end
else begin//set third color to constant value
case(thirdVal)
2'd0:
blueVal <= 10'd0;
2'd1:
blueVal <= 10'd250;
2'd2:
blueVal <= 10'd500;
2'd3:
blueVal <= 10'd750;
endcase
end
end
else begin
if
(alt && maxCount>3) begin //alternate second color
maxCount
<= 3'd0;
if
(redVal==10'd1000) begin //reset second color at 1000
redVal
<= 10'd0;
end
else begin
redVal
<= redVal + 10'd200;
end
end
end
//stat check
end
//end count check
end//end
of this case
3'd5:
begin //red up, green up (reverse is both down)
//different
wait period to cycle colors
if
(counter > countMax) begin
maxCount
<= maxCount + 3'd1;
counter
<= 16'd0;
//red
value
if
(~reverse) begin
if(redVal
< 10'd1020) begin
redVal
<= redVal + 10'd10;
end
else begin
redVal
<= 10'd0;
end
end
else begin
if
(redVal > 10'd0) begin
redVal
<= redVal - 10'd10;
end else begin
redVal
<= 10'd1020;
end
end
//green
value
if
(stat) begin //stationary second color
if
(alt) begin //alternate second color
if
(maxCount>3) begin
maxCount
<= 3'd0;
if
(greenVal==10'd1000) begin
greenVal
<= 10'd0;
end
else begin
greenVal
<= greenVal + 10'd200;
end
end
end
end
else begin
if
(reverse) begin
if
( greenVal > 10'd0) begin
greenVal
<= greenVal - 10'd10;
end
else begin
greenVal
<= 10'd1020;
end
end
else begin
if
(greenVal < 10'd1020) begin
greenVal
<= greenVal + 10'd10;
end
else begin
greenVal
<= 10'd0;
end
end
if
(alt & maxCount>3) begin //alternate third color
if
(maxCount>3) begin
maxCount
<= 3'd0;
if
(blueVal==10'd1000)begin
blueVal
<= 10'd0;
end
else begin
blueVal
<= blueVal + 10'd200;
end
end
end
else begin
//set
third color to constant value
case(thirdVal)
2'd0:
blueVal <= 10'd0;
2'd1:
blueVal <= 10'd250;
2'd2:
blueVal <= 10'd500;
2'd3:
blueVal <= 10'd750;
endcase
end
end
end
end
3'd6:
begin // red up, blue up (reverse is both down)
//different
wait period to cycle colors
if
(counter > countMax) begin
maxCount
<= maxCount + 3'd1;
counter
<= 16'd0;
//red
value
if
(~reverse) begin
if(redVal
< 10'd1020) begin
redVal
<= redVal + 10'd10;
end
else begin
redVal
<= 10'd0;
end
end
else begin
if
(redVal > 10'd0) begin
redVal
<= redVal - 10'd10;
end
else begin
redVal
<= 10'd1020;
end
end
//green
value
if
(stat) begin //stationary second color
if
(alt) begin //alternate second color
if
(maxCount>3) begin
maxCount
<= 3'd0;
if
(blueVal==10'd1000) begin
blueVal
<= 10'd0;
end
else begin
blueVal
<= blueVal + 10'd200;
end
end
end
end
else begin
if
(reverse) begin
if
( blueVal > 10'd0) begin
blueVal
<= blueVal - 10'd10;
end
else begin
blueVal
<= 10'd1020;
end
end
else begin
if
(blueVal < 10'd1020) begin
blueVal
<= blueVal + 10'd10;
end
else begin
blueVal
<= 10'd0;
end
end
if
(alt & maxCount>3) begin //alternate third color
if
(maxCount>3) begin
maxCount
<= 3'd0;
if
(greenVal==10'd1000)begin
greenVal
<= 10'd0;
end
else begin
greenVal
<= greenVal + 10'd200;
end
end
end
else begin
//set
third color to constant value
case(thirdVal)
2'd0:
greenVal <= 10'd0;
2'd1:
greenVal <= 10'd250;
2'd2:
greenVal <= 10'd500;
2'd3:
greenVal <= 10'd750;
endcase
end
end
end
end
3'd7:
begin //green up, blue up (reverse is both down)
//different
wait period to cycle colors
if
(counter > countMax) begin
maxCount
<= maxCount + 3'd1;
counter
<= 16'd0;
//red
value
if
(~reverse) begin
if(greenVal
< 10'd1020) begin
greenVal
<= greenVal + 10'd10;
end
else begin
greenVal
<= 10'd0;
end
end
else begin
if
(greenVal > 10'd0) begin
greenVal
<= greenVal - 10'd10;
end
else begin
greenVal
<= 10'd1020;
end
end
//green
value
if
(stat) begin //stationary second color
if
(alt) begin //alternate second color
if
(maxCount>3) begin
maxCount
<= 3'd0;
if
(blueVal==10'd1000) begin
blueVal
<= 10'd0;
end
else begin
blueVal
<= blueVal + 10'd200;
end
end
end
end
else begin
if
(reverse) begin
if
( blueVal > 10'd0) begin
blueVal
<= blueVal - 10'd10;
end
else begin
blueVal
<= 10'd1020;
end
end else begin
if
(blueVal < 10'd1020) begin
blueVal
<= blueVal + 10'd10;
end
else begin
blueVal
<= 10'd0;
end
end
if
(alt & maxCount>3) begin //alternate third color
if
(maxCount>3) begin
maxCount
<= 3'd0;
if
(redVal==10'd1000)begin
redVal
<= 10'd0;
end
else begin
redVal
<= redVal + 10'd200;
end
end
end
else begin
//set
third color to constant value
case(thirdVal)
2'd0:
redVal <= 10'd0;
2'd1:
redVal <= 10'd250;
2'd2:
redVal <= 10'd500;
2'd3:
redVal <= 10'd750;
endcase
end
end
end
end
endcase
end//end VGA_VS
end//end
always
assign
red = redVal;
assign
blue = blueVal;
assign
green = greenVal;
endmodule
///////////////////////////////////////////////////////////////////
//
Decode one hex digit for LED 7-seg display /////////////////////
///////////////////////////////////////////////////////////////////
module
HexDigit(segs, num);
input [3:0] num ; //the
hex digit to be displayed
output [6:0] segs ; //actual LED
segments
reg [6:0] segs ;
always @ (num)
begin
case
(num)
4'h0:
segs = 7'b1000000;
4'h1:
segs = 7'b1111001;
4'h2:
segs = 7'b0100100;
4'h3:
segs = 7'b0110000;
4'h4:
segs = 7'b0011001;
4'h5:
segs = 7'b0010010;
4'h6:
segs = 7'b0000010;
4'h7:
segs = 7'b1111000;
4'h8:
segs = 7'b0000000;
4'h9:
segs = 7'b0010000;
4'ha:
segs = 7'b0001000;
4'hb:
segs = 7'b0000011;
4'hc:
segs = 7'b1000110;
4'hd:
segs = 7'b0100001;
4'he:
segs = 7'b0000110;
4'hf:
segs = 7'b0001110;
default
segs = 7'b1111111;
endcase
end
endmodule
///////////////////////////////////////////////////////////////////
/////////////////////
Box visualization ///////////////////////////
///////////////////////////////////////////////////////////////////
module
boxVisual(reset, CLK50, AUDCLK, VGA_VS, VGA_HS, audIn, cymbal, bass, voice,
coordX, coordY, period, red, green, blue);
//
parameters
parameter
locate=1'd0, color=1'd1;
//
inputs
input
reset, CLK50, AUDCLK, VGA_VS, VGA_HS;
input
[15:0] audIn, cymbal, bass, voice;
input
[8:0] coordX, coordY;
input
[31:0] period;
//regs
reg
state;
reg
[15:0] sample, sampleCymbal, sampleBass, sampleVoice;
reg
[2:0] region;
reg
[9:0] redValue, greenValue, blueValue;
reg
[31:0] audCount;
//outputs
output
[9:0] red, green, blue;
//wires
wire
[9:0] r0red, r0green, r0blue;
wire
[9:0] r1red, r1green, r1blue;
wire
[9:0] r2red, r2green, r2blue;
wire
[9:0] r3red, r3green, r3blue;
pixelController
region0(reset, 8'd16, CLK50, CLK27, AUDCLK, VGA_VS, VGA_HS, audIn, period,
r0red, r0green, r0blue);
pixelController
region1(reset, 8'd32, CLK50, CLK27, AUDCLK, VGA_VS, VGA_HS, audIn, period,
r1red, r1green, r1blue);
pixelController
region2(reset, 8'd64, CLK50, CLK27, AUDCLK, VGA_VS, VGA_HS, audIn, period,
r2red, r2green, r2blue);
pixelController
region3(reset, 8'd128,CLK50, CLK27, AUDCLK, VGA_VS, VGA_HS, audIn, period,
r3red, r3green, r3blue);
//+audIn[14:11] -audIn[14:11]
//
logic for determining output pixel values
always
@ (posedge CLK50) begin
audCount <= audCount
+ 32'd1;
if (audCount >
(period<<4)) begin
audCount
<= 32'd0;
sample
<= audIn;
sampleCymbal
<= cymbal;
sampleBass
<= bass;
sampleVoice
<= voice;
end
if(reset)begin
state
<= locate;
end else /*if
(~VGA_VS|~VGA_HS)*/begin
case(state)
locate:
begin
if(coordX>=10'd0+sample[14:11]&coordX<=10'd46-sample[14:11])begin
// column 0
region
<= 3'd0;
end
else if (coordX>=10'd47+sampleBass[14:11]&coordX<=10'd91-sampleBass[14:11])
begin //column 1
if(coordY>=10'd0+sample[14:11]&coordY<10'd34-sample[14:11])begin
//audio
region
<= 3'd0;
end
else if (coordY>=10'd35+sampleBass[14:11]&coordY<10'd205-sampleBass[14:11])begin
// bass
region
<= 3'd1;
end
else if
(coordY>=10'd206+sample[14:11]&coordY<10'd239-sample[14:11])begin
//audio
region
<= 3'd0;
end
else begin //otherwise
region
<= 3'd4;
end
end
else if (coordX>=10'd92+sampleCymbal[14:11]&coordX<=10'd136-sampleCymbal[14:11])
begin //column 2
if(coordY>=10'd0+sample[14:11]&coordY<10'd34-sample[14:11])begin
//audio
region
<= 3'd0;
end
else if (coordY>=10'd35+sampleBass[14:11]&coordY<10'd68-sampleBass[14:11])begin//bass
region
<= 3'd1;
end
else if
(coordY>=10'd69+sampleCymbal[14:11]&coordY<10'd171-sampleCymbal[14:11])begin//cymbal
region
<= 3'd2;
end
else if
(coordY>=10'd172+sampleBass[14:11]&coordY<10'd205-sampleBass[14:11])begin//bass
region
<= 3'd1;
end
else if
(coordY>=10'd206+sample[14:11]&coordY<10'd239-sample[14:11])begin//audio
region
<= 3'd0;
end
else begin //otherwise
region
<= 3'd4;
end
end
else if (coordX>=10'd137+sampleVoice[14:11]&coordX<=10'd181-sampleVoice[14:11])
begin //column 3
if(coordY>=10'd0+sample[14:11]&coordY<10'd34-sample[14:11])begin//audio
region
<= 3'd0;
end
else if
(coordY>=10'd35+sampleBass[14:11]&coordY<10'd68-sampleBass[14:11])begin//bass
region
<= 3'd1;
end
else if
(coordY>=10'd69+sampleCymbal[14:11]&coordY<10'd102-sampleCymbal[14:11])begin//cymbal
region
<= 3'd2;
end
else if
(coordY>=10'd103+sampleVoice[14:11]&coordY<10'd136-sampleVoice[14:11])begin//voice
region
<= 3'd3;
end
else if
(coordY>=10'd137+sampleCymbal[14:11]&coordY<10'd171-sampleCymbal[14:11])begin//cymbal
region
<= 3'd2;
end
else if
(coordY>=10'd172+sampleBass[14:11]&coordY<10'd205-sampleBass[14:11])begin//bass
region
<= 3'd1;
end
else if
(coordY>=10'd206+sample[14:11]&coordY<10'd239-sample[14:11])begin//audio
region
<= 3'd0;
end
else begin//otherwise
region
<= 3'd4;
end
end
else if
(coordX>=10'd182+sampleCymbal[14:11]&coordX<=10'd226-sampleCymbal[14:11])
begin //column 4
if(coordY>=10'd0+sample[14:11]&coordY<10'd34-sample[14:11])begin//audio
region
<= 3'd0;
end
else if
(coordY>=10'd35+sampleBass[14:11]&coordY<10'd68-sampleBass[14:11])begin//bass
region
<= 3'd1;
end
else if
(coordY>=10'd69+sampleCymbal[14:11]&coordY<10'd171-sampleCymbal[14:11])begin//cymbal
region
<= 3'd2;
end
else if
(coordY>=10'd172+sampleBass[14:11]&coordY<10'd205-sampleBass[14:11])begin//bass
region
<= 3'd1;
end
else if (coordY>=10'd206+sample[14:11]&coordY<10'd239-sample[14:11])begin//audio
region
<= 3'd0;
end
else begin//otherwise
region
<= 3'd4;
end
end
else if
(coordX>=10'd227+sampleBass[14:11]&coordX<=10'd271-sampleBass[14:11])
begin //column 5
if(coordY>=10'd0+sample[14:11]&coordY<10'd34-sample[14:11])begin//audio
region
<= 3'd0;
end
else if
(coordY>=10'd35+sampleBass[14:11]&coordY<10'd205-sampleBass[14:11])begin//bass
region
<= 3'd1;
end
else if (coordY>=10'd206+sample[14:11]&coordY<10'd239-sample[14:11])begin//audio
region
<= 3'd0;
end
else begin
region
<= 3'd4;
end
end
else if (coordX>=10'd272+sample[14:11]&coordX<=10'd319-sample[14:11])
begin //column 6
region
<= 3'd0;
end
else begin
region
<= 3'd4;
end
state
<= color;
end
color:
begin
if(region==3'd0)begin
redValue
<= r0red;
greenValue
<= r0green;
blueValue
<= r0blue;
end
else if (region==3'd1)begin
redValue
<= r1red;
greenValue
<= r1green;
blueValue
<= r1blue;
end
else if (region==3'd2)begin
redValue
<= r2red;
greenValue
<= r2green;
blueValue
<= r2blue;
end
else if (region==3'd3)begin
redValue
<= r3red;
greenValue
<= r3green;
blueValue
<= r3blue;
end
else begin
redValue
<= 10'd0;
greenValue
<= 10'd0;
blueValue
<= 10'd0;
end
state
<= locate;
end
endcase
end
end
assign
red = redValue;
assign
green = greenValue;
assign
blue = blueValue;
endmodule
///////////////////////////////////////////////////////////////////////
///////////////////
SIMPLE VISUALIZATION CODE /////////////////////////
///////////////////////////////////////////////////////////////////////
wire
[31:0] mSEG7_DIG;
reg [31:0] Cont;
wire VGA_CTRL_CLK;
wire AUD_CTRL_CLK;
wire
[9:0] mVGA_R;
wire
[9:0] mVGA_G;
wire
[9:0] mVGA_B;
wire
[19:0] mVGA_ADDR; //video
memory address
wire
[9:0] Coord_X, Coord_Y; //display coods
wire DLY_RST;
assign TD_RESET = 1'b1; // Allow
27 MHz input
assign AUD_ADCLRCK = AUD_DACLRCK;
assign AUD_XCK = AUD_CTRL_CLK;
Reset_Delay r0 (.iCLK(CLOCK_50),.oRESET(DLY_RST) );
I2C_AV_Config
u3 ( // Host
Side
.iCLK(CLOCK_50),
.iRST_N(KEY[0]),
// I2C Side
.I2C_SCLK(I2C_SCLK),
.I2C_SDAT(I2C_SDAT) );
VGA_Audio_PLL
p1 ( .areset(~DLY_RST),.inclk0(CLOCK_27),.c0(VGA_CTRL_CLK),.c1(AUD_CTRL_CLK),.c2(VGA_CLK) );
//
output to audio DAC
wire
signed [15:0] audio_outL, audio_outR ;
//
input from audio ADC
wire
signed [15:0] audio_inL, audio_inR ;
//audio
codec
AUDIO_DAC_ADC
u4 ( // Audio
Side
.oAUD_BCK(AUD_BCLK),
.oAUD_DATA(AUD_DACDAT),
.oAUD_LRCK(AUD_DACLRCK),
.oAUD_inL(audio_inL),
// audio data from ADC
.oAUD_inR(audio_inR),
// audio data from ADC
.iAUD_ADCDAT(AUD_ADCDAT),
.iAUD_extL(audio_outL),
// audio data to DAC
.iAUD_extR(audio_outR),
// audio data to DAC
// Control Signals
.iCLK_18_4(AUD_CTRL_CLK),
.iRST_N(DLY_RST),
.isel(SW[17])
);
//vga
controller
VGA_Controller u1 ( // Host
Side
.iCursor_RGB_EN(4'b0111),
.oAddress(mVGA_ADDR),
.oCoord_X(Coord_X),
.oCoord_Y(Coord_Y),
.iRed(mVGA_R),
.iGreen(mVGA_G),
.iBlue(mVGA_B),
// VGA Side
.oVGA_R(VGA_R),
.oVGA_G(VGA_G),
.oVGA_B(VGA_B),
.oVGA_H_SYNC(VGA_HS),
.oVGA_V_SYNC(VGA_VS),
.oVGA_SYNC(VGA_SYNC),
.oVGA_BLANK(VGA_BLANK),
// Control Signal
.iCLK(VGA_CTRL_CLK),
.iRST_N(DLY_RST) );
assign
reset = ~KEY[0];
wire
[15:0] absoutL;
wire
signed [15:0] ToLineOutL,IIR4outL_volumed;
wire
signed [15:0] IIR4outL_voice1,IIR4outL_voice2;
wire
signed [15:0] IIR4outL_cymbal1,IIR4outL_cymbal2;
wire
signed [15:0] IIR4outL_bass1,IIR4outL_bass2;
wire
[9:0] hbitamp;
wire
signed [15:0] abstobar;
//audio
filters
///////////////////////cymbal
filtering/////////////////////////
//Filter:
cutoff=0.5 ,cheby1 high
IIR4_18bit_fixed IIR4L_cymb1(
.audio_out (IIR4outL_cymbal1),
.audio_in (audio_inL),
.scale (3'd1),
.b1 (18'hCA7),
.b2 (18'h3CD63),
.b3 (18'h4BEC),
.b4 (18'h3CD63),
.b5 (18'hCA7),
.a2 (18'h3FC41),
.a3 (18'h3A7AA),
.a4 (18'h3EE8D),
.a5 (18'h3F654),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
//Filter: cutoff=0.6 ,cheby1 low
IIR4_18bit_fixed
IIR4L_cymb2(
.audio_out (IIR4outL_cymbal2),
.audio_in (IIR4outL_cymbal1),
.scale (3'd1),
.b1 (18'h1682),
.b2 (18'h5A0A),
.b3 (18'h8710),
.b4 (18'h5A0A),
.b5 (18'h1682),
.a2 (18'h398AF),
.a3 (18'h395A5),
.a4 (18'h3EE6B),
.a5 (18'h3F6EC),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
/////////////////bass
beat filter/////////////////////////////////
//Filter:
cutoff=0.02 , cheby1 low,
IIR4_27bit
IIR4_bass1(
.audio_out (IIR4outL_bass1),
.audio_in (audio_inL>>>2),
.scale (3'd2),
.b1 (27'hF),
.b2 (27'h3E),
.b3 (27'h5D),
.b4 (27'h3E),
.b5 (27'hF),
.a2 (27'hF492E6),
.a3 (27'h6A0C0AB),
.a4 (27'hE0AA7A),
.a5 (27'h7CA00F9),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
//////////////////////////guitar/voice
filter////////////////////////////
//Filter:
cutoff=0.05 ,cheby1 high
IIR4_27bit IIR4_voice1(
.audio_out (IIR4outL_voice1),
.audio_in (audio_inL),
.scale (3'd2),
.b1 (27'h3426B9),
.b2 (27'h72F651C),
.b3 (27'h138E856),
.b4 (27'h72F651C),
.b5 (27'h3426B9),
.a2 (27'hE7331D),
.a3 (27'h6C586C9),
.a4 (27'hBED26A),
.a5 (27'h7D469AF),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
//Filter: cutoff=0.06 ,cheby1 low
//Filter:
cutoff=0.060000
IIR4_27bit
IIR4_voice2(
.audio_out (IIR4outL_voice2),
.audio_in (IIR4outL_voice1),
.scale (3'd2),
.b1 (27'hE5),
.b2 (27'h395),
.b3 (27'h560),
.b4 (27'h395),
.b5 (27'hE5),
.a2 (27'hE8252D),
.a3 (27'h6C15AFD),
.a4 (27'hC401F3),
.a5 (27'h7D26F62),
.state_clk(AUD_CTRL_CLK),
.lr_clk(AUD_DACLRCK),
.reset(reset)
)
; //end filter
//////////////////////////end
audio filters////////////////////////////////////
////////////////drawing
module////////////////////
drawBars
uBars(
.iHeight_sel(hbitamp),
.thresh1(thresh2),
.iHeight_low(barAmp_low),
.iHeight_mid(barAmp_mid),
.iHeight_high(barAmp_high),
.draw_Select(SW[3:1]),
.iX(Coord_X),
.iY(Coord_Y),
.iVGA_VS(VGA_VS),
.iVGA_HS(VGA_HS),
.oR(
mVGA_R),
.oG(
mVGA_G),
.oB(
mVGA_B),
.CLK(CLOCK_50),
.VGACLK(VGA_CTRL_CLK),
.RST(~KEY[0])
);
//////////////////////////////////////////////
assign
LEDR[15:0]=(SW[0])? avg_onoff: avg_for_Volume_Adjust;
wire
[15:0] thresh=(threshCondition)? absoutL: 0; //theshold absolute value of audio
wire
threshCondition;
assign
threshCondition=absoutL>16'h00FF && avg_onoff>16'h000F;
wire
thresh2;
assign
thresh2=absoutL>16'h07FF && avg_onoff>16'h000F;
assign
LEDG[7]=thresh2;
assign
LEDG[6]=threshCondition;
abs
uabsL(absoutL, audio_outR); //takes absolute value of input
firstHbit
hb(thresh[15:6],hbitamp,CLOCK_50); //quatize bar height with top ten bits of
threshold
wire
[15:0] avg_for_Volume_Adjust,abs_of_runningAvg;
//average
(out, in,CLK,RST);//16'd65534,Log_AL=16;
average
avgunit(avg_for_Volume_Adjust,toAvg,32'd262144,6'd18,AUD_DACLRCK,reset);
wire
[15:0] avg_onoff,abs_of_In;
average
onoff(avg_onoff,abs_of_In,32'd16384,6'd14,AUD_DACLRCK,reset);
//abs(out, in, clk);
abs
uabsavg(abs_of_In,audio_inL);
wire
[15:0] absout_bass,absout_mid,absout_high,absout_in;
abs
abs_low(absout_bass, IIR4outL_bass1); //takes absolute value of input
abs
abs_mid(absout_mid, IIR4outL_voice2);
abs
abs_high(absout_high, IIR4outL_cymbal2);
wire
[15:0] thresh_low,thresh_mid,thresh_high;
assign
thresh_low=(absout_bass>16'h00FF)? absout_bass: 0; //threshold
assign
thresh_mid=(absout_mid>16'h00FF)? absout_mid: 0;
assign
thresh_high=(absout_high>16'h00FF)? absout_high: 0;
wire
[9:0] barAmp_low,barAmp_mid,barAmp_high;
firstHbit
hb_low(avg_onoff[7:0],barAmp_low,CLOCK_50); //quatize bar height
firstHbit
hb_mid(thresh_mid[15:6],barAmp_mid,CLOCK_50);
firstHbit
hb_high(thresh_high[15:6],barAmp_high,CLOCK_50);
//SW3=volume
up/down, SW[2:0]=volume level,
//SW16:14
= filter select
//1ddd=bass
//01dd=voice
//001d=cymbal
//0001=avg
//0000=original
wire
[2:0] amp_shift;
assign
LEDG[2:0]= amp_shift;
ampCheck
ampchecktest(avg_for_Volume_Adjust,amp_shift);
wire
[15:0] toAvg;
assign
toAvg=(SW[16])? absout_bass : (SW[15])? absout_mid : (SW[14])? absout_high : 0;
assign
ToLineOutL =(SW[8])? ((SW[16])? IIR4outL_bass1 : (SW[15])? IIR4outL_voice2 :
(SW[14])? IIR4outL_cymbal2 : audio_inL): ((SW[16])?
IIR4outL_bass1<<<amp_shift : (SW[15])?
IIR4outL_voice2<<<amp_shift : (SW[14])?
IIR4outL_cymbal2<<<amp_shift : audio_inL);
assign
audio_outR = ToLineOutL ;
assign
audio_outL = 0;//outputing on this channel causes critical timing error and
breaks filters.
endmodule
//top module
////////////////////////////////////draw
bars//////////////////////////////////////
module
drawBars(iHeight_sel,thresh1,iHeight_low,iHeight_mid,iHeight_high,draw_Select,iX,iY,iVGA_VS,iVGA_HS,oR,oG,oB,CLK,VGACLK,RST);
input
thresh1;
input
[9:0] iHeight_low,iHeight_mid,iHeight_high,iHeight_sel; //height of bar
input
[9:0] iY; //VGA coordinates
input
[9:0] iX;
input
CLK,RST,VGACLK;
input
iVGA_VS,iVGA_HS; //vga sync
output
[9:0] oR,oG,oB; //vga colors
input
[2:0] draw_Select;
reg
[9:0] reg_R,reg_G,reg_B,x,y;
reg
[3:0] draw_state;
reg
[9:0] height_reg0;
reg
[9:0] height_reg1;
reg
[9:0] height_reg2;
reg
[9:0] height_reg3;
reg
[9:0] height_reg4;
reg
[9:0] height_reg5;
reg
[9:0] height_reg6;
reg
[9:0] height_reg7;
reg
[9:0] height_reg8;
reg
[9:0] height_reg9;
reg
[9:0] height_reg10;
reg
[9:0] height_reg11;
parameter
init=4'd0, color=4'd1,eyeheight=10'd20,eyewidth=10'd60;
parameter
barShiftLeft=10'd30;
wire
c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,bars;
wire
eye1,eye2;
wire
box,box2;
reg
thresh1_reg;
reg
[9:0] boxY,boxX;
wire
[5:0] eyeMod;
assign
eyeMod=height_reg0;
assign c1=iY > height_reg0 &
iX>10'd0+barShiftLeft & iX<10'd50+barShiftLeft;
assign c2=iY > height_reg1 &
iX>10'd50+barShiftLeft & iX<10'd100+barShiftLeft;
assign c3=iY > height_reg2 &
iX>10'd100+barShiftLeft & iX<10'd150+barShiftLeft;
assign c4=iY > height_reg3 &
iX>10'd150+barShiftLeft & iX<10'd200+barShiftLeft;
assign c5=iY > height_reg4 &
iX>10'd200+barShiftLeft & iX<10'd250+barShiftLeft;
assign c6=iY > height_reg5 &
iX>10'd250+barShiftLeft & iX<10'd300+barShiftLeft;
assign c7=iY > height_reg6 &
iX>10'd300+barShiftLeft & iX<10'd350+barShiftLeft;
assign c8=iY > height_reg7 &
iX>10'd350+barShiftLeft & iX<10'd400+barShiftLeft;
assign c9=iY > height_reg8 &
iX>10'd400+barShiftLeft & iX<10'd450+barShiftLeft;
assign c10=iY > height_reg9 &
iX>10'd450+barShiftLeft & iX<10'd500+barShiftLeft;
assign c11=iY > height_reg10 &
iX>10'd500+barShiftLeft & iX<10'd550+barShiftLeft;
assign c12=iY > height_reg11 &
iX>10'd550+barShiftLeft & iX<10'd600+barShiftLeft;
assign eye1= iY >10'd40+eyeMod & iY
<10'd40+eyeheight+eyeMod & iX >10'd140+eyeMod & iX
<10'd140+eyewidth-eyeMod;
assign eye2= iY >10'd40+eyeMod & iY
<10'd40+eyeheight+eyeMod & iX >10'd480+eyeMod & iX
<10'd480+eyewidth-eyeMod;
assign box= iY >10'd440-boxY & iY
<10'd479-boxY & iX >10'd0+boxX & iX <10'd40+boxX;// iY
==10'd228-eyeMod | iY ==10'd250+eyeMod| iX ==10'd309-eyeMod | iX
==10'd331+eyeMod;
assign
box2=iY >10'd120 & iY
<10'd360 & iX >10'd170 & iX <10'd510;
assign
bars=( c1 | c2 | c3 | c4 | c5 |
c6 | c7 | c8 | c9 | c10 | c11 | c12);
parameter
waitCycles=32'd2;
reg
[31:0] waitCount;
reg
boxX_direction;
always
@ (posedge CLK) begin
if(RST) begin
waitCount<=32'd0;
draw_state<=init;
height_reg0<=0;
height_reg1<=0;
height_reg2<=0;
height_reg3<=0;
height_reg4<=0;
height_reg5<=0;
height_reg6<=0;
height_reg7<=0;
height_reg8<=0;
height_reg9<=0;
height_reg10<=0;
height_reg11<=0;
boxY<=0;
boxX<=0;
boxX_direction<=1;
end
else begin
case(draw_state)
init:
begin
if(waitCount<waitCycles)
begin //delay fetch of new bar heights
waitCount<=waitCount+1;
if(draw_Select==3'b000)
begin
if(height_reg0
< 10'd479) begin
height_reg0<=height_reg0+20;
height_reg1<=height_reg2+20;
height_reg2<=height_reg2+20;
height_reg3<=height_reg3+20;
height_reg4<=height_reg4+20;
height_reg5<=height_reg5+20;
height_reg6<=height_reg6+20;
height_reg7<=height_reg7+20;
height_reg8<=height_reg8+20;
height_reg9<=height_reg9+20;
height_reg10<=height_reg10+20;
height_reg11<=height_reg11+20;
end
end
else
if(draw_Select==3'b001) begin
height_reg0<=height_reg0+20;
end
draw_state<=color;
end
//delay
else
begin //get new bar height
if(draw_Select==3'b000)
begin
height_reg0<=10'd479-iHeight_sel;
height_reg1<=10'd479-iHeight_sel;
height_reg2<=10'd479-iHeight_sel;
height_reg3<=10'd479-iHeight_sel;
height_reg4<=10'd479-iHeight_sel;
height_reg5<=10'd479-iHeight_sel;
height_reg6<=10'd479-iHeight_sel;
height_reg7<=10'd479-iHeight_sel;
height_reg8<=10'd479-iHeight_sel;
height_reg9<=10'd479-iHeight_sel;
height_reg10<=10'd479-iHeight_sel;
height_reg11<=10'd479-iHeight_sel;
waitCount<=0;
end
else
if (draw_Select==3'b001) begin
height_reg0<=10'd479-iHeight_sel;
height_reg1<=10'd479;
height_reg2<=10'd479;
height_reg3<=10'd479;
height_reg4<=10'd479;
height_reg5<=10'd479;
height_reg6<=10'd479;
height_reg7<=10'd479;
height_reg8<=10'd479;
height_reg9<=10'd479;
height_reg10<=10'd479;
height_reg11<=10'd479;
end
else
if (draw_Select==3'b010) begin
if(boxY<10'd440
& thresh1) begin //Y motion
boxY<=boxY+10;
//impulse up
end
else
if(boxY>10'd0) begin
boxY<=boxY-1;
//gravity
end
if(boxX_direction)
begin
if(boxX<10'd600)
begin //X motion
boxX<=boxX+1;
end
else
begin
boxX_direction<=0;
//change direction
end
end
else
begin
if(boxX>10'd0)
begin
boxX<=boxX-1;
end
else
begin
boxX_direction<=1;
end
end
height_reg0<=10'd479-iHeight_sel;
height_reg1<=10'd479;
height_reg2<=10'd479;
height_reg3<=10'd479;
height_reg4<=10'd479;
height_reg5<=10'd479;
height_reg6<=10'd479;
height_reg7<=10'd479;
height_reg8<=10'd479;
height_reg9<=10'd479;
height_reg10<=10'd479;
height_reg11<=10'd479;
end
else
if (draw_Select==3'b011) begin
end
else
if (draw_Select==3'b111) begin
thresh1_reg<=thresh1;
end
else
begin
boxY<=0;
boxX<=0;
end
draw_state<=color;
end
//new bar height
end
color:
begin
//if(
bars | box ) begin // c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 | c11 |
c12 | eye1 | eye2
//
if(switchColor) begin
if((bars
& ~(iY%40 ==0)) & ( draw_Select==3'b000)) begin //single bar big
reg_R<=10'h0;
reg_G<=10'h0;
reg_B<=10'hfff;
end
else
if((bars & ~(iY%40 ==0)) & (draw_Select==3'b001)) begin //single bar
small
reg_R<=10'h0;
reg_G<=10'h0;
reg_B<=10'hfff;
end
else
if(box & draw_Select==3'b010) begin
reg_R<=10'h0;
reg_G<=10'h0;
reg_B<=10'hfff;
end
else
if(box2 & draw_Select==3'b011) begin
if(thresh1)
begin
reg_R<=10'h0;
reg_G<=10'hfff;
reg_B<=10'h0;
end
end
else
if(box2 & draw_Select==3'b111 & thresh1_reg) begin
reg_R<=10'h0;
reg_G<=10'hfff;
reg_B<=10'h0;
end
else
begin
reg_R<=10'h0;
reg_G<=10'h0;
reg_B<=10'h0;
end
if(vs_sig)
//finished drawing
draw_state<=init;
end
endcase
end //VGA sync
end
//always
assign
state=draw_state;
reg
vs_state;
reg
vs_sig;
always
@ (posedge CLK) begin //generate a one cycle pulse on each v sync,signals a
fully drawn screen
if(RST) begin
vs_state<=0;
end
else begin
case(vs_state)
0:
begin
vs_sig<=0;
if(~iVGA_VS)
begin
vs_sig<=1;
vs_state<=1;
end
end
1:
begin
vs_sig<=0;
if(iVGA_VS)
vs_state<=0;
end
endcase
end
end
assign
oR= reg_R;
assign
oG= reg_G;
assign
oB= reg_B;
endmodule
/////////////////////////////////////////////////////////////////////////////
//////////////absolute
value///////////////////////
module
abs(out, in);
output [15:0] out ;
input wire signed [15:0]
in ;
assign out
=(in[15])?-in:in;
endmodule
//////////////////////////////////////////////////
module
firstHbit(in,out,CLK);
input
CLK;
input
[9:0] in;
output
[9:0] out;
reg
[9:0] out_reg;
always
begin
if(in[9])
out_reg<=10'd479;
else if(in[8])
out_reg<=10'd360;
else if(in[7])
out_reg<=10'd320;
else if(in[6])
out_reg<=10'd280;
else if(in[5])
out_reg<=10'd240;
else if(in[4])
out_reg<=10'd200;
else if(in[3])
out_reg<=10'd160;
else if(in[2])
out_reg<=10'd120;
else if(in[1])
out_reg<=10'd80;
else if(in[0])
out_reg<=10'd40;
else
out_reg<=10'd0;
end
//always
assign
out=out_reg;
endmodule
///////////////////////////running
avg/////////////////////////////
module
runnigAvg(out,in,AVGLENG,LOG_AVGLENG,CLK,RST);
//takes
running average of input over AVGLENG samples
//input
is aasumed to be signed
//AVGLENG
must be power of two
input
signed [15:0] in;
output
signed [15:0] out;
input
[15:0] AVGLENG;
input
[5:0] LOG_AVGLENG;
input
CLK,RST;
reg
signed [31:0] accum;
reg
[3:0] state;
reg
signed [31:0] oldestinput;
reg
[15:0] sampleCount;
parameter
add1=0,add2=1, add3=2;
parameter
avgLength=16'd256,Log_AL=8;
wire
signed [31:0] inExtended;
assign
inExtended= {{16{in[15]}},in};
always
@ (posedge CLK) begin
if(RST) begin
accum<=0;
state<=add1;
oldestinput<=0;
sampleCount<=0;
end
else begin
case(state)
add1:
begin
accum<=
accum + inExtended;
oldestinput<=
inExtended;
sampleCount<=sampleCount+1;
state<=add2;
end
add2:
begin
accum<=
accum + inExtended;
if(sampleCount
<avgLength) begin
state<=add2;
sampleCount<=sampleCount+1;
end
else
begin
state<=add2;
accum<=
accum - oldestinput;
oldestinput<=
inExtended;
sampleCount<=0;
end
end
endcase
end //rst else
end
//always
wire
signed [31:0] divAccum;
assign
divAccum=accum>>>Log_AL;
assign
out=divAccum[15:0];
endmodule
///////////////////////////////////////////////////////////
module
average (out, in,AVGLENG,LOG_AVGLENG,CLK,RST);
//takes
average of input over AVGLENG samples
//then
reset to zero and repeats
//input
is aasumed to be positive
//AVGLENG
must be power of two
//ouput
is held constant until a new average is calculated
output [15:0] out ;
input [15:0] in ;
input [31:0] AVGLENG;
input [5:0] LOG_AVGLENG;
input CLK;
input RST;
reg [31:0] accum;
reg [31:0] sampleCount;
wire [31:0] inExtended;
reg [31:0] outReg;
assign inExtended=
{{16{1'b0}},in};
//parameter
avgLength=16'd65534,Log_AL=16;
always @(posedge CLK)
begin
if(RST)
begin
accum<=0;
sampleCount<=0;
outReg<=0;
end
else
begin
if(sampleCount<AVGLENG) begin
accum<=accum+inExtended;
sampleCount<=sampleCount+1;
end
else begin
outReg<=accum>>LOG_AVGLENG;
sampleCount<=0;
accum<=0;
end
end
end //always
assign out=outReg[15:0];
endmodule
module
ampCheck(in,amp);
input
[15:0] in;
output
reg [2:0] amp;
always
begin
if(in[15])
amp<=3'd0;
else if(in[14])
amp<=3'd0;
else if(in[13])
amp<=3'd0;
else if(in[12])
amp<=3'd0;
else if(in[11])
amp<=3'd0;
else if(in[10])
amp<=3'd0;
else if(in[9])
amp<=3'd0;
else if(in[8])
amp<=3'd1;
else if(in[7])
amp<=3'd1;
else if(in[6])
amp<=3'd1;
else if(in[5])
amp<=3'd2;
else if(in[4])
amp<=3'd3;
else if(in[3])
amp<=3'd5;
else if(in[2])
amp<=3'd0;
else if(in[1])
amp<=3'd0;
else if(in[0])
amp<=3'd0;
else
amp<=10'd0;
end
//always
endmodule
%%%%%%%%%%%%%%%%%%%%%%%%%%MATLAB
FILTER TESTING%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear all
close all
clc
song='s1';
%load music
[Yjunk,FS,NBITS]=wavread(['C:\Users\Darbin\Desktop\',song,'.wav'],1);
st=10*FS;
secs=10;
y=wavread(['C:\Users\Darbin\Desktop\',song,'.wav'],[st
st+secs*FS]);
Y1=y(:,1); %channel 1
Y2=y(:,2); %channel 2
order=4;
select=1;
%%%%%%%%%%%%%%%%%%%%%%%%%%LOW
PASS%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if(select==1)
ds=4;
avgLeng=2^4;
[b,a]=cheby1(order,1,.03); % bass beat
%Y=downsample(Y1,ds);
Y=filter(b,a,Y1);
%Y=upsample(Y,ds);
%
Y=filter((1/avgLeng)*ones(1,avgLeng),1,Y);
% Y=Y*(1/max(Y));
% Y(abs(Y)<.2)=0;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%FFT
PLOT%%%%%%%%%%%%%%%%%%%%%%
if(select==-1)
L=length(Y1);
NFFT = 2^nextpow2(L); % Next
power of 2 from length of y
Yfft = fft(Y1,NFFT)/L;
f = FS/2*linspace(0,1,NFFT/2+1);
% Plot single-sided
amplitude spectrum.
plot(f,2*abs(Yfft(1:NFFT/2+1)))
title('Single-Sided
Amplitude Spectrum of y(t)')
xlabel('Frequency
(Hz)')
ylabel('|Y(f)|')
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%HIGH
PASS%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if(select==2)
s1=.9;
ds=4;
avgLeng=2^2;
%Y=downsample(Y1,ds);
[b,a]=cheby1(order,1,s1,'high'); %cymbal
Y=filter(b,a,Y1);
[b,a]=cheby1(order,1,s1+.03,'low'); %cymbal
Y=filter(b,a,Y);
%Y=upsample(Y,ds);
Y=filter((1/avgLeng)*ones(1,avgLeng),1,Y);
Y=Y*(1/max(Y));
Y(abs(Y)<.2)=0;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%BAND
PASS%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if(select==3)
s=.05;
[b,a]=cheby1(order,1,s,'high'); %guitar/voice
Y=filter(b,a,Y1);
[b,a]=cheby1(order,1,s+.01,'low');
Y=filter(b,a,Y);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sound(Y,FS); %play sound
%clear playsnd %kills music
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Michael Lyons - mpl56 - ECE5760
% draw bar generation code
% declare wires needed for
column detection
fprintf('wire ')
for i = 0:99
fprintf('c%i,', i)
end
% declare all the height
registers
fprintf('\n')
for i = 0:99
fprintf('reg [9:0] height_reg%i;\n', i)
end
% assign the column logic
fprintf('\n')
inc = 6
for i = 0:99
fprintf('assign c%i=iY > height_reg%i & iX>10d%i &
iX<10d%i;\n', i,i,i*inc,i*inc+inc)
end
% reset all the height
registers
fprintf('\n')
for i = 0:99
fprintf('height_reg%i<=0;\n',i)
end
% shifting all the height
registers over by one
fprintf('\n')
for i = 0:99
if i == 0
fprintf('height_reg%i <=
10d479-iHeight;\n', i)
else
fprintf('height_reg%i <=
height_reg%i;\n', i, i-1)
end
end
% create the if statement to
check for VGA controller in a column
fprintf('\n')
fprintf('if((')
for i = 0:99
if i==99
fprintf('c%i)', i)
else
fprintf('c%i|', i)
end
end
%fprintf('& ~(iY%40 ==0)
| eye1 | eye2) begin')
fprintf('\n')