summaryrefslogtreecommitdiffstats
path: root/Graphic_Equalizer/src
diff options
context:
space:
mode:
authorOliver Schinagl <oliver@schinagl.nl>2004-12-09 14:03:54 (GMT)
committerOliver Schinagl <oliver@schinagl.nl>2004-12-09 14:03:54 (GMT)
commit460b179c5c7700c8c19e2f4906ed4c99681b6227 (patch)
tree7eab5caaf9175fa2a8f60fa455ba3e2ff82aa26b /Graphic_Equalizer/src
parent149677eca198a58c2a8f5c94eedc0d294f2ed82c (diff)
downloadTASS-460b179c5c7700c8c19e2f4906ed4c99681b6227.zip
TASS-460b179c5c7700c8c19e2f4906ed4c99681b6227.tar.gz
TASS-460b179c5c7700c8c19e2f4906ed4c99681b6227.tar.bz2
New branch used to add new features.
Diffstat (limited to 'Graphic_Equalizer/src')
-rw-r--r--Graphic_Equalizer/src/audio.hcc102
-rw-r--r--Graphic_Equalizer/src/display.hcc338
-rw-r--r--Graphic_Equalizer/src/eventhandler.hcc315
-rw-r--r--Graphic_Equalizer/src/events.hcc76
-rw-r--r--Graphic_Equalizer/src/fft.hcc505
-rw-r--r--Graphic_Equalizer/src/main.hcc162
-rw-r--r--Graphic_Equalizer/src/mouse.hcc131
-rw-r--r--Graphic_Equalizer/src/runfft.hcc182
-rw-r--r--Graphic_Equalizer/src/smartmedia.hcc233
9 files changed, 2044 insertions, 0 deletions
diff --git a/Graphic_Equalizer/src/audio.hcc b/Graphic_Equalizer/src/audio.hcc
new file mode 100644
index 0000000..91901e1
--- /dev/null
+++ b/Graphic_Equalizer/src/audio.hcc
@@ -0,0 +1,102 @@
+/*! @file audio.hcc
+ *
+ * @section generic Audio init and main loop
+ *
+ * @section project Project information.
+ * Project Graphic Equalizer\n
+ * @author O.M. Schinagl
+ * @date 20041011
+ * @version 0.1
+ *
+ * @section copyright Copyright
+ * Copyright ©2004 Koninklijke Philips Electronics N.V. All rights reserved
+ *
+ * @section history Change history
+ * 20041011: \n Initial version
+ *
+ ********************************************************************/
+
+/******** System Includes *************/
+#include <stdlib.hch>
+
+#include "pal_master.hch"
+
+/******** Application Includes ********/
+#include "configuration.hch"
+#include "audio.hch"
+
+
+
+/*! \fn macro proc audio_init(gain_level, input_source, sample_rate, AUDIOIN, AUDIOOUT)
+ *
+ * \brief Set some inital values to the audio hardware.
+ *
+ * \param gain_level Set the input amplifier to this amplification
+ * level.
+ * \param input_source Choose between microphone input or linein
+ * input.
+ * \param sample_rate Set the sample rate between 8000
+ * and 48000
+ *
+ * \return void
+ * \retval void
+ *
+ */
+macro proc audio_init(gain_level, input_source, sample_rate, AUDIOIN, AUDIOOUT) {
+ /*
+ * We simply call the appropiate handlers and pass values along. We
+ * Don't set the mute on input gain. We have volume control to do this.
+ * Input and Output sampling rates are equal. We dont' need different
+ * rates.
+ */
+ RC200AudioInSetGain(FALSE, gain_level, gain_level);
+ RC200AudioInSetInput(input_source);
+ PalAudioInSetSampleRate(AUDIOIN, sample_rate);
+ PalAudioOutSetSampleRate(AUDIOOUT, sample_rate);
+} /* --- audio_init() --- */
+
+
+#if !USE_RUNFFT
+//TODO: put runfft here!
+/*! @fn macro proc audio_main(audiodata, AUDIOIN, AUDIOOUT);
+ *
+ * @brief Main audiodriver. This function never returns! It calls the
+ * audiohandlers and stores samples into a global array. Once 64
+ * Samples are collected it raises a signal AUDIO_READY to let
+ * other processes know it's ready. We use quadruple buffering for
+ * audio input and double buffering for audio output.
+ *
+ * @param *audiodata pointer to audio information structure.
+ * @param AUDIOIN Audio Input Handler
+ * @param AUDIOOUT Audio Output Handler
+ *
+ * @return Never Returns.
+ * @retval void
+ */
+macro proc audio_main(audiodata, AUDIOIN, AUDIOOUT) {
+ /*
+ * Determin the data width for the current platform.
+ */
+ macro expr IW = PalAudioInGetMaxDataWidthCT();
+ macro expr OW = PalAudioOutGetMaxDataWidthCT();
+
+ signed IW sample_left_in, sample_right_in;
+ signed OW sample_left_out, sample_right_out;
+
+ while (TRUE) {
+ PalAudioInRead(AUDIOIN, &sample_left_in, &sample_right_in);
+
+/* par {
+ sample_add(sample_left_in);
+ sample_get(&sample_left_out);
+ sample_right_out = sample_right_in;
+ }
+ if (rotate_samples()) {
+ / *
+ * 64 Samples have been processed, calculate.
+ * /
+ }
+*/ PalAudioOutWrite(AUDIOOUT, (signed OW)(sample_left_in @ 0), (signed OW)(sample_right_in @ 0));
+ }
+} /* --- audio_main() --- */
+#endif
diff --git a/Graphic_Equalizer/src/display.hcc b/Graphic_Equalizer/src/display.hcc
new file mode 100644
index 0000000..1aeb9d9
--- /dev/null
+++ b/Graphic_Equalizer/src/display.hcc
@@ -0,0 +1,338 @@
+/*! \file display.hcc
+ *
+ * \section generic Message build up information and more
+ *
+ * \section project Project information.
+ * Project Graphic Equalizer\n
+ * \author O.M. Schinagl
+ * \date 20041011
+ * \version 0.1
+ *
+ * \section copyright Copyright
+ * Copyright ©2004 Koninklijke Philips Electronics N.V. All rights reserved
+ *
+ * \section history Change history
+ * 20041011: O.M. Schinagl\n Initial version
+ *
+ ********************************************************************/
+
+/*
+ * Set the Clock rate for this domain. 25.175 Mhz is required for the Video output.
+ */
+#define PAL_TARGET_CLOCK_RATE 25175000
+
+/******** System Includes *************/
+#include <stdlib.hch>
+
+#include "pal_master.hch"
+
+/******** Application Includes ********/
+#include "configuration.hch"
+#include "audio.hch"
+#include "eventhandler_shared.hch"
+#include "mouse_shared.hch"
+#include "smartmedia_shared.hch"
+#include "display_shared.hch"
+#include "display.hch"
+
+#if HAVE_DEBUG
+ #include "debug.hch"
+#endif
+
+
+
+/*
+ * Channel to notify others when new mousedata is available. If so
+ * Then mousedata struct is updated with shared data.
+ */
+chan unsigned 1 maskupdate_notification;
+
+
+
+/*! \fn void display_main(skindata_t *skindata, audiodata_t *audiodata, events_t *events, mousedata_t *mousedata)
+ *
+ * \brief This routine handles all drawing of pixels. It never returns!
+ *
+ * \param *skindata struct with all skin information.
+ * \param *audiodata struct with (i)fft data to be drawn.
+ * \param *events struct with all events.
+ * \param *mousedata struct with coordinates to current.
+ * X en Y.
+ *
+ * \return Never Returns.
+ * \retval void
+ */
+void display_main(skindata_t *skindata, audiodata_t *audiodata, events_t *events, mousedata_t *mousedata) {
+ /*
+ * Setup macro's RAM/Video handles and to coordinate pixel writing.
+ */
+ macro expr CLOCKRATE = PAL_ACTUAL_CLOCK_RATE;
+ macro expr VIDEOOUT = PalVideoOutOptimalCT(CLOCKRATE);
+ macro expr RAM_BANK0 = PalPL2RAMCT(0);
+ macro expr DW = PalPL2RAMGetMaxDataWidthCT();
+ macro expr AW = PalPL2RAMGetMaxAddressWidthCT();
+ macro expr VISIBLEX = PalVideoOutGetVisibleX(VIDEOOUT, CLOCKRATE);
+ macro expr TOTALX = PalVideoOutGetTotalX(VIDEOOUT, CLOCKRATE);
+ macro expr TOTALY = PalVideoOutGetTotalY(VIDEOOUT);
+ macro expr SCANX = PalVideoOutGetX(VIDEOOUT);
+ macro expr SCANY = PalVideoOutGetY(VIDEOOUT);
+
+ unsigned DW pixeldata;
+ unsigned 24 visual_graph_color;
+ unsigned AW address, address_offset;
+
+
+
+ /*
+ * If the passed button_state tells us the button is active, then we
+ * the button is 'on' and we draw it inverted. Otherwise we draw the
+ * area of the button normally.
+ */
+ macro proc draw_button(button_state) {
+ if (button_state == pixeldata[31:24]) {
+ PalVideoOutWrite(VIDEOOUT, ~PIXEL);
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ }
+
+ /*
+ * Prime Rendering Pipeline to start where the skin starts.
+ */
+ PalPL2RAMSetReadAddress(RAM_BANK0, ADDRESS_SKIN_START);
+
+ /*
+ * Run the following tasks indefinatly and in parallel
+ */
+ while (TRUE) {
+ par {
+ /*
+ * Before starting this loop we allready set the the
+ * address. Therefor we can start reading the
+ * previously set address and prepare the next address
+ * for the next cycle.
+ */
+ PalPL2RAMRead(RAM_BANK0, &pixeldata);
+ PalPL2RAMSetReadAddress(RAM_BANK0, address_offset +address);
+
+ /*
+ */
+ switch (events->mode) {
+ case MODE_HELP:
+ address_offset = ADDRESS_HELP_START;
+ break;
+ case MODE_GRAPH:
+ address_offset = ADDRESS_GRAPHMASK_START;
+ break;
+ default:
+ address_offset = ADDRESS_SKIN_START;
+ break;
+ }
+
+ if (MODE_GRAPH == events->mode) {
+ par {
+ visual_graph_color = ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[31:24]]) << 1) @ ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[31:24]]) << -1) @ ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[31:24]]) << 0);
+ PalVideoOutWrite(VIDEOOUT, 0 @ visual_graph_color);
+ }
+ } else {
+ /*
+ * Determin what to draw where here. Every case has an
+ * if else statement comparing wether to draw something
+ * special or the background. Every specific drawing
+ * obviously only happens in the masked area.
+ */
+ switch (pixeldata[31:24]) {
+ /*
+ */
+ case AREA_WAVEFORM:
+ if (SCANY == 0 @ skindata->area_waveform_bottom -(0 @ (audiodata->ifft_info.read[((SCANX -(0 @ skindata->area_waveform_left)) <-8)]))) {
+ PalVideoOutWrite(VIDEOOUT, skindata->color_area_waveform);
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ break;
+
+ /*
+ * Volume control over the Y-axis.
+ */
+ case AREA_VOLUME_YAXIS:
+ /*
+ * The volume_position stores the
+ * highest point of our bar. Every
+ * pixel after this point is drawn.
+ */
+ if (SCANY >= 0 @ events->volume_position) {
+ PalVideoOutWrite(VIDEOOUT, skindata->color_area_volume);
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ break;
+
+ /*
+ * Spectrum Analyzer
+ */
+ case AREA_SPECTRUM_ANALYZER:
+ /*
+ * We draw every pixel that is smaller TODO
+ */
+ if ((SCANY >= (0 @ skindata->area_spectrum_bottom) -(0 @ audiodata->fft_info.read[(SCANX -(0 @ skindata->area_spectrum_left))[9:2]])) && ((SCANX -(0 @ skindata->area_spectrum_left)) <- 2)) {
+ PalVideoOutWrite(VIDEOOUT, PIXEL_SPECTRUM);
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ break;
+
+ /*
+ * Since all buttons are drawn equally, either
+ * we draw them normally or we inverse them, we
+ * can handle them almost equally.
+ */
+ case BUTTON_PRESET_1: /* fall through */
+ case BUTTON_PRESET_2: /* fall through */
+ case BUTTON_PRESET_3: /* fall through */
+ case BUTTON_PRESET_4: /* fall through */
+ case BUTTON_PRESET_5: /* fall through */
+ case BUTTON_PRESET_6:
+ /*
+ * The active preset tells us what
+ * button is currently enabled. We must
+ * however not forget to add the preset
+ * button offset to possibly match it
+ * with the current mask.
+ */
+ draw_button((events->active_preset +BUTTON_PRESET_1) <- 8);
+ break;
+
+ case BUTTON_PRECISE: /* fall through */
+ case BUTTON_CONCAVE_HALF: /* fall through */
+ case BUTTON_CONVEX_HALF: /* fall through */
+ case BUTTON_CONCAVE_FULL: /* fall through */
+ case BUTTON_CONVEX_FULL:
+ /*
+ * equalizer mode tells us what button
+ * is currently enabled. By adding the
+ * equalizer mode button offset we can
+ * safley check wether it matches our
+ * mask.
+ */
+ draw_button((0 @ events->equalizer_mode) +BUTTON_PRECISE);
+ break;
+
+ case BUTTON_LOG:
+ /*
+ *
+ */
+ draw_button((0 @ audiodata->display_log) +BUTTON_LOG);
+ break;
+
+ /*
+ * The default case is split up into two parts
+ * actually. This is because we have 128 bands
+ * for the equalizer and thus as many mask
+ * entries. Since we don't want 128 identical
+ * cases we check wether the equalizer mask is
+ * currently active and if so draw it. If this
+ * is not the case we simply draw the
+ * background.
+ */
+ default:
+ /* (pixeldata[31:24] <= AREA_EQUALIZER_MAX) && */
+ if ((AREA_EQUALIZER_MIN <= pixeldata[31:24]) && (!events->locked_display)) {
+ if ((SCANY == 0 @ events->equalizer_display[(pixeldata[31:24] -AREA_EQUALIZER_MIN) <- 7]) || ((SCANY +1) == 0 @ events->equalizer_display[(pixeldata[31:24] -AREA_EQUALIZER_MIN) <- 7])) {
+ PalVideoOutWrite(VIDEOOUT, skindata->color_equalizer);
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ break;
+ }
+ }
+
+ /*
+ * We compare our current X and Y scan positions of the
+ * output to the x and y data of the mouse. When those
+ * are equal we set the current mask to the mask stored
+ * in memory at that location. We then know what mask
+ * is to be used for events.
+ */
+ if (MOUSE_UPDATED == mousedata->status) {
+ if ((SCANX == 0 @ mousedata->x) && (SCANY == 0 @ mousedata->y)) {
+ par {
+ events->mask = pixeldata[31:24];
+ mousedata->status = MOUSE_NOT_UPDATED;
+ maskupdate_notification ! MOUSE_UPDATED;
+ }
+ } else {
+ delay;
+ }
+ } else {
+ delay;
+ }
+
+ /*
+ * The current position of the screen can lay in an
+ * area called the blanking area. We don't have data
+ * for this area as it is not drawn. We therefor have
+ * to determin wether we are beyond the visible area of
+ * the screen, but before the end of the total width of
+ * the screen. Our pipeline consists of 5 total stages.
+ * Therefor we have to substract 5 pixels.
+ */
+ if ((SCANX > (VISIBLEX - 5)) && (SCANX <= (TOTALX - 5))) {
+ /*
+ * We are in the blanking area of the screen.
+ * If we are on the last line, and thus last
+ * pixel we reset our address counter.
+ */
+ if (SCANY == (TOTALY -1)) {
+ /*
+ * Reset our draw address counter to 0.
+ */
+ address = 0;
+ } else {
+ /*
+ * We have reached the end of the
+ * visible line, but not the end of
+ * the screen. Therefore do nothing.
+ */
+ delay;
+ }
+ } else {
+ /*
+ * Increase the memory counter for each pixel
+ * drawn thus keeping the memory location in
+ * sync with the current pixel position.
+ */
+ address++;
+ }
+ }
+ }
+} /* --- display_main() --- */
+
+
+
+/*! \fn void reload_equalizer(events_t *events, unsigned 4 *equalizer_levels)
+
+ * \brief This function copies the supplied equalizer values to the array
+ * used for displaying equalizer data.
+ *
+ * \param *events events struct
+ * \param *equalizer_levels pointer to 128 entries where equalizer
+ * is to be copied from.
+ *
+ * \return void
+ * \retval void
+ */
+void reload_equalizer(events_t *events, unsigned 4 *equalizer_levels) {
+ unsigned 7 equalizer_band;
+
+ events->locked_display = TRUE;
+ delay;
+ do {
+ events->equalizer_display[equalizer_band] = equalizer_table_inv[equalizer_levels[equalizer_band]];
+ equalizer_band++;
+ } while (equalizer_band);
+ events->locked_display = FALSE;
+} /* --- reload_equalizer() --- */
diff --git a/Graphic_Equalizer/src/eventhandler.hcc b/Graphic_Equalizer/src/eventhandler.hcc
new file mode 100644
index 0000000..e1f90ae
--- /dev/null
+++ b/Graphic_Equalizer/src/eventhandler.hcc
@@ -0,0 +1,315 @@
+/*! \file eventhandler.hcc
+ *
+ * \section generic This modules coordinates all events. Thus for example
+ * when the mousehandler registers a 'click' we coordinate
+ * the actions that follow that click.
+ *
+ * \section project Project information.
+ * Project Graphic Equalizer\n
+ * \author O.M. Schinagl
+ * \date 20041110
+ * \version 0.1
+ *
+ * \section copyright Copyright
+ * Copyright ©2004 Koninklijke Philips Electronics N.V. All rights reserved
+ *
+ * \section history Change history
+ * 20041110: O.M. Schinagl\n Initial version
+ *
+ ********************************************************************/
+
+/******** System Includes *************/
+#include <stdlib.hch>
+
+#include "pal_master.hch"
+
+/******** Application Includes ********/
+#include "configuration.hch"
+#include "audio.hch"
+#include "mouse_shared.hch"
+#include "eventhandler_shared.hch"
+#include "eventhandler.hch"
+#include "events.hch"
+#include "display_shared.hch"
+#include "display.hch"
+
+#if HAVE_DEBUG
+ #include "debug.hch"
+#endif
+
+
+
+/*
+ */
+extern chan unsigned 1 maskupdate_notification;
+
+
+
+/*! \fn void eventhandler_main(audiodata_t *audiodata, events_t *events, mousedata_t *mousedata);
+ * \brief
+ *
+ * \param *audiodata pointer to struct for setting equalizer levels.
+ * \param *events pointer to struct with all events for display states.
+ * \param *mousedata pointer to struct with mouse data for X and Y
+ * coordinates.
+ *
+ * \return Never Returns.
+ * \retval void
+ */
+void eventhandler_main(audiodata_t *audiodata, events_t *events, mousedata_t *mousedata) {
+ mpram {
+ ram unsigned 4 write[768];
+ rom unsigned 4 read[768];
+ } equalizer_levels with { block = "BlockRAM"};
+
+ unsigned 10 preset_offset;
+ unsigned 10 reference_point, reference_point_right;
+ unsigned 5 volume_left;
+ unsigned 4 index_offset, index_end;
+ unsigned 4 equalizer_mode_local;
+ unsigned 1 newmaskupdate;
+
+ load_preset(LOAD_PRESET_RESET, equalizer_levels.write);
+ reload_equalizer(events, &equalizer_levels.write[preset_offset]);
+
+ while (TRUE) {
+ maskupdate_notification ? newmaskupdate;
+
+ /*
+ * First we determine what mousestate we currently have. Then
+ * we check where we are to decide what to do.
+ */
+ switch (mousedata->state) {
+ case MOUSE_STATE_ON_PRESS:
+ /*
+ * If we are displaying the graphic visual,
+ * any press returns to the application.
+ */
+ if (MODE_GRAPH == events->mode) {
+ events->mode = MODE_SKIN;
+ events->mask = 0;
+ } else {
+ delay;
+ }
+
+ /*
+ */
+ if (BUTTON_MODE == events->mask) {
+ if (MODE_GRAPH == events->mode) {
+ events->mode = MODE_SKIN;
+ } else {
+ events->mode = MODE_GRAPH;
+ }
+ } else {
+ delay;
+ }
+
+ /*
+ * If the current mask equals the help button
+ * we set display mode to help.
+ */
+ if (BUTTON_HELP == events->mask) {
+ /*
+ * Change the mode to help if it's
+ * currently not set, otherwise go back
+ * to skin mode.
+ */
+ if (MODE_HELP == events->mode) {
+ events->mode = MODE_SKIN;
+ } else {
+ events->mode = MODE_HELP;
+ }
+ } else {
+ delay;
+ }
+
+ /*
+ * The Preset buttons span from 1 to 6 so if
+ * the mask one of those, we'll change the
+ * pointer to point to the current preset.
+ */
+ if ((BUTTON_PRESET_1 <= events->mask) && (events->mask <= BUTTON_PRESET_6)) {
+ /*
+ * The active preset is determined by
+ * the mask minus an offset. Hence
+ * ranging our active preset from 0 to
+ * 6.
+ */
+ events->active_preset = 0 @ (events->mask -BUTTON_PRESET_1);
+ /*
+ * Each equalizer is 128 bands wide,
+ * thus we need to add 128 * the preset
+ * for each different preset. This
+ * offset is calculated here.
+ */
+ preset_offset = events->active_preset << 7;
+ /*
+ * We set the pointer to the active
+ * part of the array by using the
+ * preset offset as our index. Hence
+ * depending on the selected preset
+ * we point to 0, 128, 256, 384, 512
+ * or 640.
+ */
+ audiodata->equalizer_levels_ptr = &equalizer_levels.read[preset_offset];
+ /*
+ * Finally update the equalizer bars
+ * that are drawn by the display.
+ */
+ reload_equalizer(events, &equalizer_levels.write[preset_offset]);
+ } else {
+ delay;
+ }
+
+ if ((BUTTON_PRECISE <= events->mask) && (events->mask <= BUTTON_CONVEX_FULL)) {
+ events->equalizer_mode = (events->mask -BUTTON_PRECISE) <-4;
+ } else {
+ delay;
+ }
+
+ /*
+ * If the demo button was pressed load the
+ * demo preset values into the presets.
+ */
+ if (BUTTON_DEMO == events->mask) {
+ load_preset(LOAD_PRESET_DEMO, equalizer_levels.write);
+ reload_equalizer(events, &equalizer_levels.write[preset_offset]);
+ }
+
+ /*
+ * If the reset button was pressed load the
+ * reset values into the presets.
+ */
+ if (BUTTON_RESET == events->mask) {
+ load_preset(LOAD_PRESET_RESET, equalizer_levels.write);
+ reload_equalizer(events, &equalizer_levels.write[preset_offset]);
+ }
+
+ /*
+ * If the current mask equals the log button,
+ * we flip the display_log bit.
+ */
+ if (BUTTON_LOG == events->mask) {
+ audiodata->display_log = !audiodata->display_log;
+ } else {
+ delay;
+ }
+
+ break;
+
+ case MOUSE_STATE_DOWN:
+ /*
+ * If we are in the volume area we update the
+ * volume level for both channels.
+ */
+ if (AREA_VOLUME_YAXIS == events->mask) {
+ /*
+ * Copy the current Y cursor position
+ * to the events struct. This we then
+ * later use for drawing purposes.
+ */
+ events->volume_position = 0 @ mousedata->y;
+ /*
+ * Look the relative y-coordinate up in
+ * the volumecontrol lookup table. We
+ * make a local copy here because the
+ * RC200 call doesn't behave nicely
+ * when passing anything else.
+ */
+ volume_left = volumecontrol_table[((mousedata->y) -65) <- 6];
+ /*
+ * We feel that volume gets softer the
+ * closer it gets to the 0, and louder
+ * as it approaches 0x1f. The SetVolume
+ * RC200 call does this in an unnatural
+ * reverse way. Therefor we fix it.
+ */
+ RC200AudioOutSetVolume(!volume_left, 0x1f -volume_left, 0x1f -volume_left);
+ } else {
+ delay;
+ }
+
+ if ((AREA_EQUALIZER_MIN <= events->mask) && (events->mask <= AREA_EQUALIZER_MAX)) {
+
+ if (EQUALIZERMODE_PRECISE == events->equalizer_mode) {
+ events->locked_display = TRUE;
+ equalizer_levels.write[preset_offset +(0 @ events->mask) -AREA_EQUALIZER_MIN] = equalizer_table[mousedata->y -382];
+ events->equalizer_display[(events->mask -AREA_EQUALIZER_MIN) <- 7] = mousedata->y;
+ events->locked_display = FALSE;
+ } else {
+
+ equalizer_mode_local = events->equalizer_mode +1;
+
+ events->locked_display = TRUE;
+ index_offset = ((equalizer_mode_local << 1)); /* delay; */
+
+ if (events->mask < (AREA_EQUALIZER_MIN +(0 @ equalizer_mode_local))) {
+ reference_point = events->equalizer_display[AREA_EQUALIZER_MIN -AREA_EQUALIZER_MIN];
+ index_offset -= (((0 @ equalizer_mode_local) -(events->mask -AREA_EQUALIZER_MIN)) <- 4);
+ } else {
+ reference_point = events->equalizer_display[(events->mask - (0 @ equalizer_mode_local) -AREA_EQUALIZER_MIN) <- 7];
+ index_offset -= 1;
+ }
+
+ if (events->mask > (AREA_EQUALIZER_MAX -(0 @ equalizer_mode_local))) {
+ reference_point_right = events->equalizer_display[AREA_EQUALIZER_MAX -AREA_EQUALIZER_MIN];
+ index_end = (((0 @ equalizer_mode_local) -(AREA_EQUALIZER_MAX -events->mask)) <- 4) -1;
+ } else {
+ reference_point_right = events->equalizer_display[(events->mask + (0 @ equalizer_mode_local) -AREA_EQUALIZER_MIN) <- 7];
+ index_end = 0;
+ }
+ events->locked_display = FALSE;
+
+ for (; index_offset != index_end; index_offset--) {
+ unsigned 10 average_bar;
+ unsigned 7 equalizer_index;
+ unsigned 4 bar_index;
+
+ if (index_offset == equalizer_mode_local) {
+ reference_point = reference_point_right;
+ } else {
+ delay;
+ }
+
+ if (index_offset > equalizer_mode_local)
+ {
+ bar_index = (index_offset -equalizer_mode_local);
+ equalizer_index = ((events->mask -(0 @ bar_index) -AREA_EQUALIZER_MIN) <- 7);
+ } else
+ {
+ bar_index = (equalizer_mode_local -index_offset);
+ equalizer_index = ((events->mask +(0 @ bar_index) -AREA_EQUALIZER_MIN) <- 7);
+ }
+
+ if (reference_point > mousedata->y) {
+ average_bar = mousedata->y +((reference_point -mousedata->y) >> (equalizer_mode_local -bar_index));
+ } else {
+ average_bar = mousedata->y -((mousedata->y -reference_point) >> (equalizer_mode_local -bar_index));
+ }
+
+ events->locked_display = TRUE;
+ equalizer_levels.write[preset_offset +(0 @ equalizer_index)] = equalizer_table[average_bar -382];
+ events->equalizer_display[equalizer_index] = average_bar;
+ events->locked_display = FALSE;
+ }
+ }
+ } else {
+ delay;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
+} /* --- eventhandler_main() --- */
+
+
+
+/*
+ * Volume Control lookuptable.
+ * TODO: This table is now hardcoded. To ensure full skinability this table
+ * should be dynamically loaded.
+ */
+rom unsigned 5 volumecontrol_table[46] = {31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0};
diff --git a/Graphic_Equalizer/src/events.hcc b/Graphic_Equalizer/src/events.hcc
new file mode 100644
index 0000000..2e8c272
--- /dev/null
+++ b/Graphic_Equalizer/src/events.hcc
@@ -0,0 +1,76 @@
+/*! \file events.hcc
+ *
+ * \section generic This module contains the various actions and events
+ * that need to be performed.
+ *
+ * \section project Project information.
+ * Project Graphic Equalizer\n
+ * \author O.M. Schinagl
+ * \date 20041710
+ * \version 0.1
+ *
+ * \section copyright Copyright
+ * Copyright ©2004 Koninklijke Philips Electronics N.V. All rights reserved
+ *
+ * \section history Change history
+ * 20041710: O.M. Schinagl\n Initial version
+ *
+ *****************************************************************************/
+
+
+
+/******** System Includes *************/
+#include <stdlib.hch>
+
+#include "pal_master.hch"
+
+/******** Application Includes ********/
+#include "configuration.hch"
+#include "eventhandler_shared.hch"
+#include "events.hch"
+
+#if HAVE_DEBUG
+ #include "debug.hch"
+#endif
+
+
+ram unsigned 8 presets_default_values[768] = {
+#include "presets_hardcoded.txt"
+};
+
+
+
+/*! \fn void load_preset(unsigned 10 preset, unsigned 4 *equalizer_levels_ptr);
+ * \brief This function loads 768 4bits presets into the equalizer_levels
+ * array pointed to by equalizer_levels.
+ *
+ * \param *equalizer_levels Location where to store presets loaded
+ * from blockram.
+ *
+ * \return void
+ * \retval void
+ */
+void load_preset(unsigned 10 preset, unsigned 4 *equalizer_levels_ptr) {
+ unsigned 10 equalizer_index;
+ unsigned 4 temp;
+
+ equalizer_index = 0;
+ while (equalizer_index != 768) {
+ temp = presets_default_values[preset +(0 @ (equalizer_index \\ 1))][7:4];
+ equalizer_levels_ptr[equalizer_index] = temp;
+ temp = presets_default_values[preset +(0 @ (equalizer_index \\ 1))][3:0];
+ equalizer_levels_ptr[equalizer_index +1] = temp;
+
+ equalizer_index += 2;
+ }
+} /* --- load_preset() --- */
+
+
+
+/*
+ * Equalizer lookuptabes.
+ * TODO: This table is now hardcoded. To ensure full skinability this table
+ * should be dynamically loaded.
+ */
+ram unsigned 4 equalizer_table[640] = {15, 15, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0};
+ram unsigned 10 equalizer_table_inv[16] = {446, 444, 440, 436, 432, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 384};
diff --git a/Graphic_Equalizer/src/fft.hcc b/Graphic_Equalizer/src/fft.hcc
new file mode 100644
index 0000000..0be69fe
--- /dev/null
+++ b/Graphic_Equalizer/src/fft.hcc
@@ -0,0 +1,505 @@
+/*! \file fft.hcc
+ *
+ * \section generic This modules will take care of the actual FFT calculation
+ * on the samples. Besides the FFT this module also will
+ * equalize the audio signal according to the setting made by the user.
+ *
+ * \section project Project information.
+ * Project Graphic Equalizer\n
+ * \author M. Lauwerijssen
+ * \date 20041110
+ * \version 0.1
+ *
+ * \section copyright Copyright
+ * Copyright ©2004 Koninklijke Philips Electronics N.V. All rights reserved
+ *
+ * \section history Change history
+ * 20041110: M. Lauwerijssen\n Initial version
+ *
+ ********************************************************************/
+#include <stdlib.hch>
+#include "pal_master.hch"
+
+#include "audio.hch"
+#include "weights_256.hch"
+#include "configuration.hch"
+#include "xilinxmult.hch"
+#include "fft.hch"
+
+#if HAVE_DEBUG
+ #include "debug.hch"
+#endif
+
+/* Define two multi-port RAMs for FFT calculation; one for real and one for imaginary values
+ * Extra block RAM settings are defined to make sure read and write actions can be performed
+ * within one clock-cycle.
+ * Left out extra settings on new board the clock changes TODO !!!!
+ */
+#if HARDWARE_MULTIPLY
+mpram
+{
+ ram signed 18 rwrite[256];
+ rom signed 18 read[256];
+} real with {block = "BlockRAM"/*, westart=2.5, welength=1, rclkpos={1.5}, wclkpos={3}, clkpulselen=0.5*/};
+
+mpram
+{
+ ram signed 18 rwrite[256];
+ rom signed 18 read[256];
+} imaginary with {block = "BlockRAM"/*, westart=2.5, welength=1, rclkpos={1.5}, wclkpos={3}, clkpulselen=0.5*/};
+#else
+mpram
+{
+ ram signed 24 rwrite[256];
+ rom signed 24 read[256];
+} real with {block = "BlockRAM"/*, westart=2.5, welength=1, rclkpos={1.5}, wclkpos={3}, clkpulselen=0.5*/};
+
+mpram
+{
+ ram signed 24 rwrite[256];
+ rom signed 24 read[256];
+} imaginary with {block = "BlockRAM"/*, westart=2.5, welength=1, rclkpos={1.5}, wclkpos={3}, clkpulselen=0.5*/};
+#endif
+// multiplication factors for equalizer function
+ram signed 7 eq_settings[16] = {0,2,4,7,10,13,16,19,22,26,30,35,41,48,55,63};
+
+#if HARDWARE_MULTIPLY
+#define DC_COMPONENT 0
+#else
+#define DC_COMPONENT 8470527
+#endif
+
+/*! \fn macro proc multiply(result, op_a, op_b);
+ * \brief Procedure used for multiply-ing
+ *
+ * \param result variable containing the result of the multiply procedure
+ * \param op_a integer value to be multiplied.
+ * \param op_b integer value to be multiplied.
+ *
+ * \return Procedure returns through variable.
+ * \retval signed 36
+ */
+macro proc multiply(result, op_a, op_b)
+{
+#if HARDWARE_MULTIPLY
+ xilinxmult(result, op_a, adjs(op_b,18));
+#else
+ result = (adjs(op_a,38))*(adjs(op_a,38));
+#endif
+}
+
+
+
+
+/*! \fn void calculate_fft(unsigned 1 select_inverse)
+ * \brief This routine performs the Fast Fourier Transform for calculation of the frequency spectrum
+ *
+ * \param select_inverse determines if a FFT or iFFT has to be calculated
+ *
+ * \return nothing
+ * \retval void
+ *
+ * cost 12391 cycles
+ */
+void calculate_fft(unsigned 1 select_inverse)
+{
+ unsigned 4 level;
+ unsigned 8 point1,point2,j,f,k;
+ unsigned 9 e,i;
+ signed 16 weight1,weight2;
+#if HARDWARE_MULTIPLY
+ signed 18 p,q,r,t;
+#else
+ signed 24 p,q,r,t;
+#endif
+ signed a,b;
+
+#if HARDWARE_MULTIPLY
+ // Macro to provide rescaling of 36-bit result of fixed point multiply
+ // down to an 18-bit result. The range of bits selected depends on the
+ // number that represents the value of "1" in the trig function lookup
+ // tables. (Eg. for 16384 == 1, the lowest bit selected should be [14]).
+ macro expr rescale (x) = (x[35] @ x[30:14]);
+#else
+ //Macro to rescale the multiply result down to a 24-bit value.
+ macro expr rescale (x) = ((x>>FRACBITS)<-24);
+#endif
+
+ for(level=1;level<=NUMBER_OF_COLUMNS;level++) // count all the columns
+ {
+ e=1<<(NUMBER_OF_COLUMNS-level+1); // number of points in each block in this column
+ f=(e>>1)<-8; // number of butterflies in each block in this column
+
+ for(j=1;j<=f;j++) // count all the butterflies in each block
+ {
+ par
+ {
+ // Weight factors for real (the same for FFT and iFFT)
+ weight1 = weight_re[((j-1)<<(level-1))<-7];
+
+
+ // Weight factors for imaginary (opposite for FFT and iFFT)
+ weight2 = (!select_inverse) ? (weight_im[((j-1)<<(level-1))<-7]) : -(weight_im[((j-1)<<(level-1))<-7]);
+
+ /* ORIGINAL CODE BELOW, MODIFIED BECAUSE OF MISMATCHING OUTPUT WITH BORLAND TESTAPP
+ weight2 = (!select_inverse) ? -(weight_im[((j-1)<<(level-1))<-7]) : weight_im[((j-1)<<(level-1))<-7];
+ */
+
+
+
+ for(i=0@j;i<=NUMBER_OF_POINTS;i+=e) // count all the blocks in this column
+ { // Butterfly calculation
+ par
+ {
+ point1 = ((i<-8)-1);
+ point2 = (((i<-8)+f)-1);
+ }
+
+ par
+ {
+ p = (real.read[point1] >> 1) + (real.rwrite[point2] >> 1);
+ q = (imaginary.read[point1] >> 1) + (imaginary.rwrite[point2] >> 1);
+ }
+
+ par
+ {
+ r = (real.read[point1] >> 1) - (real.rwrite[point2] >> 1);
+ t = (imaginary.read[point1] >> 1) - (imaginary.rwrite[point2] >> 1);
+ }
+
+ multiply(a,r,weight1);
+ multiply(b,t,weight2);
+
+ par
+ {
+ real.rwrite[point2] = (rescale(a-b));
+ imaginary.rwrite[point1] = q;
+ }
+
+ multiply(a,t,weight1);
+ multiply(b,r,weight2);
+
+ par
+ {
+ real.rwrite[point1] = p;
+ imaginary.rwrite[point2] = (rescale(a+b));
+ }
+
+ }
+ }
+ }
+ }
+
+ j=1;
+ for(i=1;i<NUMBER_OF_POINTS;i++)
+ {
+ if(i<(0@j))
+ {
+ par
+ {
+ point1=j-1;
+ point2=(i-1)<-8;
+ }
+ /*
+ COPYING ARRAY VALUES FROM ONE PLACE TO ANOTHER IN THE ARRAT MUST BE DONE IN
+ 2 STEPS. FIRSTLY THE VALUES ARE COPIED TO SEPARATE VARIABLES AFTER THAT THEY
+ ARE COPIED BACK TO THEIR NEW POSITION IN THE ARRAY. THIS MUST BE DONE TO
+ PREVENT TIMING ISSUES FROM OCCURING.
+ */
+ par
+ {
+ p = real.read[point1];
+ q = imaginary.read[point1];
+ }
+ par
+ {
+ r = real.read[point2];
+ t = imaginary.read[point2];
+ }
+ par
+ {
+ real.rwrite[point1] = r;
+ imaginary.rwrite[point1] = t;
+ }
+ par
+ {
+ real.rwrite[point2] = p;
+ imaginary.rwrite[point2] = q;
+ }
+ }
+
+ k = NUMBER_OF_POINTS>>1;
+
+
+ while(k<j)
+ {
+ j = j-k;
+ k = k>>1;
+ }
+
+ j+=k;
+ }
+
+}
+
+/*! \fn void perform_fft(signed 18 *pcm_audio)
+ * \brief This routine obtains the audio data from the audio I/O component and copies this
+ * data to local arrays for calculating purposes, and calls the FFT algorithm.
+ *
+ * \param *pcm_audio pointer to array containg the audio data
+ *
+ * \return nothing
+ * \retval void
+ *
+ * cost 258 cycles (excl. the calculate FFT function)
+ */
+#if HARDWARE_MULTIPLY
+void perform_fft(signed 18 *pcm_audio)
+#else
+void perform_fft(signed 16 *pcm_audio)
+#endif
+{
+ unsigned 8 k;
+#if HARDWARE_MULTIPLY
+ signed 18 sample;
+ k=0;
+ sample = adjs(pcm_audio[k],18);
+#else
+ signed 24 sample;
+ k=0;
+ sample = adjs(pcm_audio[k],24);
+#endif
+
+ //initialize variables for the copying pipeline
+
+
+ // copy audio data to real-array before starting FFT calculation
+ // and set imaginary values to zero
+ do
+ {
+ //Copying the array values has been pipelined to prevent parallel access to the
+ //pcm_audio array. This copying procedure must be finished before another
+ //sample is read from the audio input. The time available for this loop is
+ //determined by the sampling rate of 44,1 Khz
+ par
+ {
+ //COPYING NEEDS TO BE DONE IN 2 STEPS, BECAUSE THE VALUE THAT NEEDS TO WRITTEN
+ //TO THE REAL-RAM NEEDS TO BE AVAILABLE ON THE START OFF THE CLOCKCYCLE.
+#if HARDWARE_MULTIPLY
+ sample = adjs(pcm_audio[k+1],18);
+#else
+ sample = adjs(pcm_audio[k+1],24);
+#endif
+ real.rwrite[k] = sample;
+ imaginary.rwrite[k] = 0;
+ k++;
+ }
+ } while (k);
+
+
+
+#if PERFORM_FFT_CALCULATION
+ calculate_fft(0);
+#endif
+
+
+}
+
+/*! \fn void perform_ifft(signed 18 *modified_audio, unsigned 6 *ifft_info)
+ * \brief This routine calls the ifft algorithm and after completing that it obtains the
+ * modified audio data and copies that to the output arrays of the audio I/O component.
+ * Besides that it also fills the array used by the display routine for displaying the waveform.
+ *
+ * \param *modified_audio pointer to array containg the audio data
+ * \param *ifft_info Pointer to the ifft_info array containing the modified waveform data for display purposes
+ *
+ * \return nothing
+ * \retval void
+ *
+ * cost 258 cycles (excl. the calculate iFFT function)
+ */
+#if HARDWARE_MULTIPLY
+void perform_ifft(signed 18 *modified_audio, unsigned 6 *ifft_info)
+#else
+void perform_ifft(signed 16 *modified_audio, unsigned 6 *ifft_info)
+#endif
+{
+ unsigned 6 k;
+#if HARDWARE_MULTIPLY
+ signed 18 p;
+#else
+ signed 24 p;
+#endif
+#if PERFORM_FFT_CALCULATION
+ calculate_fft(1);
+#endif
+
+ k=0;
+//initialize variables for the copying pipeline
+#if PERFORM_FFT_CALCULATION
+ #if HARDWARE_MULTIPLY
+ p = (real.read[(0@k)+95] << NUMBER_OF_COLUMNS);
+ #else
+ p = (real.read[(0@k)+95] >> NUMBER_OF_COLUMNS);
+ #endif
+#else
+ p = (real.read[(0@k)+95]);
+#endif
+
+ do
+ {
+ //Copying the array values has been pipelined to prevent parallel access to the
+ //pcm_audio array. This copying procedure must be finished before another
+ //sample is read from the audio input. The time available for this loop is
+ //determined by the sampling rate of 44,1 Khz
+ par
+ {
+ /*
+ * Before copying the modified audio from the local real-array
+ * to the output array of the audio I/O component, compensate
+ * for the FFT calculation by shifting the values.
+ * 95 is added to start the output from the middle of the sliding
+ * window, this is done to get a better sound quality.
+ */
+#if PERFORM_FFT_CALCULATION
+ #if HARDWARE_MULTIPLY
+ p = (real.read[(0@k)+95] << NUMBER_OF_COLUMNS);
+ #else
+ p = (real.read[(0@k)+95] >> NUMBER_OF_COLUMNS);
+ #endif
+#else
+ p = (real.read[(0@k)+95]);
+#endif
+ //Copy the modified audio from the local real array to the output array of the audio I/O component.
+#if HARDWARE_MULTIPLY
+ modified_audio[k] = p ;
+#else
+ modified_audio[k] = (p<-16);
+#endif
+ //Fill the array for displaying the waveform, only the 6 MSB are needed.
+ ifft_info[k] = (unsigned 6)(32+(p[17:12]));
+ k++;
+ }
+ } while(k);
+}
+
+/*! \fn void equalize_audio(audiodata_t *audiodata)
+ * \brief This routine equalizes the frequencies derived by the FFT calculation,
+ * according to the settings of the equalizer bars.
+ *
+ * \note Cost: 3844 clock cycles (Maximum)
+ *
+ * \param *audiodata pointer to the audiodata struct, containing the eq_info, etc.
+ *
+ * \return void
+ * \retval void
+ *
+ */
+void equalize_audio(audiodata_t *audiodata)
+{
+#if HARDWARE_MULTIPLY
+ signed 18 p,q;
+#else
+ signed 24 p,q;
+#endif
+ signed 18 a;
+ unsigned 8 i, mirror_i, bit, m, n;
+ unsigned 7 old_value;
+ unsigned 9 tmp;
+
+ //macro expr equalize_bar = multiply(q,a)[29:6];
+
+ macro proc equalize_bar(retval)
+ {
+ signed result;
+ multiply(result, q,a);
+#if HARDWARE_MULTIPLY
+ retval = result[23:6]; //drop last 6 bit to compensate the maximum multiplication with 64 from the eq_settings array
+#else
+ retval = result[29:6]; //drop last 6 bit to compensate the maximum multiplication with 64 from the eq_settings array
+#endif
+ }
+
+ p = real.read[0] - DC_COMPONENT; // remove DC component for calculations
+ real.rwrite[0] = p;
+
+ for(i=0;i!=NUMBER_OF_FREQUENCIES;i++)
+ {
+
+ // set multiplication factor (0..64) for current frequency bar, The first frequency band must be equalized at 100% (63) since there is no DC-component taken into account.
+ a = adjs(eq_settings[audiodata->equalizer_levels_ptr[i <- 7]],18);
+
+
+ // multiply frequency with this factor and divide by 64 (drop 6 LSB's)
+ q = real.read[i];
+ equalize_bar(p);
+ real.rwrite[i] = p;
+
+ q = imaginary.read[i];
+ equalize_bar(p);
+ imaginary.rwrite[i] = p;
+
+ // the upper part(128..255) of the spectrum is mirrored to the lower part;
+ // these values need to be adjusted too
+ if ((i<-7)!=0) // if not in DC component bar
+ {
+ mirror_i = (NUMBER_OF_POINTS-1)-i+1;
+ q = real.read[mirror_i];
+ equalize_bar(p);
+ real.rwrite[mirror_i] = p;
+
+ q = imaginary.read[mirror_i];
+ equalize_bar(p);
+ imaginary.rwrite[mirror_i] = p;
+ }
+ }
+
+ //write data to fft_info for display purposes
+ for(i=0;i<NUMBER_OF_FREQUENCIES;i++)
+ {
+ p = real.read[i];
+ q = imaginary.read[i];
+#if HARDWARE_MULTIPLY
+ if (p[17] == 1) p = -p; else delay;
+ if (q[17] == 1) q = -q; else delay;
+#else
+ if (p[23] == 1) p = -p; else delay;
+ if (q[23] == 1) q = -q; else delay;
+#endif
+ p = (p<q) ? q : p; // This is done to get the best visual frequency result
+
+ if (!audiodata->display_log)
+ {
+
+ bit=126;
+#if HARDWARE_MULTIPLY
+ while ((p[15] == 0) && (bit != 0))
+#else
+ while ((p[21] == 0) && (bit != 0))
+#endif
+ par
+ {
+ p = p<<1;
+ bit = bit - 18;
+ }
+ old_value = audiodata->fft_info.write[0 @ (i <- 7)];
+ tmp = ((0@old_value) + (0@bit))>>1;
+ audiodata->fft_info.write[0 @ (i <- 7)] = (old_value <= (tmp<-7)) ? (tmp<-7) : old_value-1;
+ }
+ else
+ {
+ old_value = audiodata->fft_info.write[0 @ (i <- 7)];
+#if HARDWARE_MULTIPLY
+ audiodata->fft_info.write[0 @ (i <- 7)] = (old_value<=(unsigned)(p[15:9])) ? (unsigned)(p[15:9]) : old_value-1;
+#else
+ audiodata->fft_info.write[0 @ (i <- 7)] = (old_value<=(unsigned)(p[21:15])) ? (unsigned)(p[21:15]) : old_value-1;
+#endif
+ }
+ }
+
+ // add DC component again before inverse FFT calculation is performed
+
+ p = real.read[0] + DC_COMPONENT;
+ real.rwrite[0] = p;
+}
+
diff --git a/Graphic_Equalizer/src/main.hcc b/Graphic_Equalizer/src/main.hcc
new file mode 100644
index 0000000..78918b8
--- /dev/null
+++ b/Graphic_Equalizer/src/main.hcc
@@ -0,0 +1,162 @@
+/*! \file main.hcc
+ *
+ * \section generic Message build up information and more
+ *
+ * \section project Project information.
+ * Project Graphic Equalizer\n
+ * \author O.M. Schinagl
+ * \date 20041011
+ * \version 0.1
+ *
+ * \section copyright Copyright
+ * Copyright ©2004 Koninklijke Philips Electronics N.V. All rights reserved
+ *
+ * \section history Change history
+ * 20041011: O.M. Schinagl\n Initial version
+ *
+ *****************************************************************************/
+
+/*
+ * Set the Clock rate for this domain. 25.175 Mhz is required for the Video output.
+ */
+#define PAL_TARGET_CLOCK_RATE 25175000
+
+/******** System Includes *************/
+#include "pal_master.hch"
+
+/******** Application Includes ********/
+#include "configuration.hch"
+#include "audio.hch"
+#include "mouse_shared.hch"
+#include "mouse.hch"
+#include "eventhandler_shared.hch"
+#include "eventhandler.hch"
+#include "display_shared.hch"
+#include "display.hch"
+#include "smartmedia.hch"
+
+#include "fft.hch"
+#include "runfft.hch"
+
+#if HAVE_DEBUG
+ #include "debug.hch"
+#endif
+
+/*! \fn void main(void);
+ * \brief Main Application Loop.
+ *
+ * \return void
+ * \retval void
+ */
+void main(void) {
+ /*
+ * Set VideoOut, Audio I/O and Ram Handles and set clockrate.
+ */
+ macro expr ClockRate = PAL_ACTUAL_CLOCK_RATE;
+ macro expr VideoOut = PalVideoOutOptimalCT(ClockRate);
+ macro expr AudioIn = PalAudioInCT(0);
+ macro expr AudioOut = PalAudioOutCT(0);
+ macro expr RAM_BANK0 = PalPL2RAMCT(0);
+
+ mousedata_t mousedata;
+ events_t events;
+ audiodata_t audiodata;
+ skindata_t skindata;
+ unsigned 1 result;
+
+ /*
+ * Check library versions and Request various hardware functionality.
+ * We need at least Major Version 1. For Audio purposes we need atleast
+ * minor version 2.
+ */
+ PalVersionRequire(1, 2);
+ PalVideoOutRequire(1);
+ PalAudioInRequire(1);
+ PalAudioOutRequire(1);
+
+ /*
+ * We verify some datawidths here at compile time. This to ensure
+ * successfull operation.
+ */
+ assert (PalVideoOutGetColorWidthCT(VideoOut) == 24, 0,
+ "We need a 24-bit color Display.");
+ assert (PalPL2RAMGetDataWidthCT(RAM_BANK0) >= 32, 0,
+ "We can't work with anything less then 32 bits wide ram.");
+
+ /*
+ * Run The Following main tasks in parallel.
+ */
+ par {
+ /*
+ * Primary task is to 'Run' several hardware simultaniously.
+ */
+ PalVideoOutRun(VideoOut, ClockRate);
+ MouseRun(ClockRate);
+ PalAudioInRun(AudioIn, ClockRate);
+ PalAudioOutRun(AudioOut, ClockRate);
+ PalPL2RAMRun(RAM_BANK0, ClockRate);
+#if HAVE_SMARTMEDIA
+ /*
+ * The smartmedia device needs the CPLD to run also.
+ */
+ CPLDRun(ClockRate);
+ SmartMediaRun(ClockRate);
+#endif
+#if HAVE_DEBUG
+ RC200RS232Run(RC200RS232_115200Baud, RC200RS232ParityNone,
+ RC200RS232FlowControlNone, ClockRate);
+#endif
+
+ /*
+ * Parallel to our Primary tasks we run the application.
+ */
+ seq {
+ /*
+ * But first we need to initialize Video and Audio.
+ * We also load the data from the SmartMedia card
+ * into the ram.
+ */
+#if HAVE_DEBUG
+ print_cls();
+ print_string("Graphic Equalizer 2");
+ print_eol();
+#endif
+ PalVideoOutEnable(VideoOut);
+ PalAudioInEnable(AudioIn);
+ PalAudioOutEnable(AudioOut);
+ audio_init(6, LINE_IN, SR_44100, AudioIn, AudioOut);
+#if HAVE_SMARTMEDIA
+ /*
+ * Once we properly setup the SmartMedia we load our
+ * data folowed by our main program loop.
+ */
+ result = smartmedia_init();
+ if (!result) {
+#endif
+ smartmedia_loaddata(&skindata);
+
+ /*
+ * Main application starts here!
+ */
+ par {
+ /*
+ * From here we run the mouse driver, audio
+ * and display in parallel. None of these
+ * should ever return.
+ */
+ mouse_main(&mousedata);
+ display_main(&skindata, &audiodata, &events, &mousedata);
+ eventhandler_main(&audiodata, &events, &mousedata);
+ audio_main(audiodata, AudioIn, AudioOut);
+ }
+#if HAVE_SMARTMEDIA
+ } else {
+#if HAVE_DEBUG
+ print_string("Error Initializing SmartMedia");
+#endif
+ }
+#endif
+ }
+ }
+
+} /* --- main() --- */
diff --git a/Graphic_Equalizer/src/mouse.hcc b/Graphic_Equalizer/src/mouse.hcc
new file mode 100644
index 0000000..61ce619
--- /dev/null
+++ b/Graphic_Equalizer/src/mouse.hcc
@@ -0,0 +1,131 @@
+/*! \file mouse.hcc
+ *
+ * \section generic This module takes care of mouse input. The mouse
+ * input function itself is however performed by the
+ * touchscreen of the RC200.
+ *
+ * \section project Project information.
+ * Project Graphic Equalizer\n
+ * \author O.M. Schinagl
+ * \date 20041011
+ * \version 0.1
+ *
+ * \section copyright Copyright
+ * Copyright ©2004 Koninklijke Philips Electronics N.V. All rights reserved
+ *
+ * \section history Change history
+ * 20041011: O.M. Schinagl\n Initial version
+ *
+ ********************************************************************/
+
+/******** System Includes *************/
+#include <stdlib.hch>
+
+#include "pal_master.hch"
+#include "pal_mouse.hch"
+
+/******** Application Includes ********/
+#include "configuration.hch"
+#include "mouse_shared.hch"
+#include "mouse.hch"
+
+#if HAVE_DEBUG
+ #include "debug.hch"
+#endif
+
+
+
+/*! \fn void mouse_main(mousedata_t *mousedata);
+ * \brief Main mousedriver. This function never returns! It calls the
+ * main mousehandler and returns the States and coordinates
+ * into a shared store.
+ *
+ * \param *mousedata Storage for all mousedata and states.
+ *
+ * \return Never Returns.
+ * \retval void
+ */
+void mouse_main(mousedata_t *mousedata) {
+ unsigned 18 touch_sampler;
+ unsigned 10 x, oldx;
+ unsigned 9 y, oldy;
+ unsigned 3 mousestate, oldmousestate;
+ unsigned 1 touch, touched, oldtouched;
+
+ /*
+ * We only check for mouse states once every 2^18 time. This to
+ * overcome the sampling of the 'Touch' state of the RC200 libs. When
+ * using newer libs this might be overkill, e.g. smaller values may
+ * work or sampling all together will be redundant.
+ */
+ touch_sampler = 1;
+ while (TRUE) {
+ if (!touch_sampler) {
+ /*
+ * We are here ready to set mouse states. We compare
+ * current and previous states and thereby determine
+ * the state to send to others
+ */
+ if (touched) {
+ if(oldtouched) {
+ mousestate = MOUSE_STATE_DOWN;
+ } else {
+ mousestate = MOUSE_STATE_ON_PRESS;
+ }
+ oldtouched = TRUE;
+ } else {
+ if(oldtouched) {
+ mousestate = MOUSE_STATE_ON_RELEASE;
+ } else {
+ mousestate = MOUSE_STATE_UP;
+ }
+ oldtouched = FALSE;
+ }
+ /*
+ * We have now processed our Touch. Reset it for the
+ * next run.
+ */
+ touched = FALSE;
+
+ /*
+ * In the rare occurance that we receive values
+ * beyond our range, we set them to some sane
+ * values here.
+ */
+ x = (x > 639) ? 0 : x;
+ y = (y > 479) ? 0 : y;
+
+ /*
+ * Compare Previous States and Coordinates to determine
+ * wether they have changed. If so, Copy them into
+ * shared memory, notify the listening processes and
+ * Set the new as previous values for the next run. We
+ * can only do this when the display has handled all
+ * changes.
+ */
+ if (((oldmousestate != mousestate) || (oldx != x) || (oldy != y)) && (MOUSE_NOT_UPDATED == mousedata->status)) {
+ //par {
+ oldx = x;
+ oldy = y;
+ oldmousestate = mousestate;
+ mousedata->x = x;
+ mousedata->y = 0 @ y;
+ mousedata->state = mousestate;
+ mousedata->status = MOUSE_UPDATED;
+ //}
+ }
+ }
+
+ /*
+ * Read the current X and Y of the 'cursor' and register wether
+ * the display was touched. If touched store this in a local
+ * store. This we do to catch the sampling of the RC200 lib.
+ */
+ RC200TouchScreenReadScaled(&x, &y, &touch);
+ if (touch) {
+ touched = TRUE;
+ }
+
+ touch_sampler++;
+ }
+} /* --- mouse_main() --- */
diff --git a/Graphic_Equalizer/src/runfft.hcc b/Graphic_Equalizer/src/runfft.hcc
new file mode 100644
index 0000000..55d4b05
--- /dev/null
+++ b/Graphic_Equalizer/src/runfft.hcc
@@ -0,0 +1,182 @@
+/*! \file runfft.hcc
+ *
+ * \section generic This module will handle the audio I/O. It will ensure the
+ * audiosamples are correctly buffered and fed correctly to the FFT.\n
+ * This module will also handle the output of the modified audio samples.
+ *
+ * \section project Project information.
+ * Project Graphic Equalizer\n
+ * \author M. Lauwerijssen
+ * \date 20041110
+ * \version 0.1
+ *
+ * \section copyright Copyright
+ * Copyright ©2004 Koninklijke Philips Electronics N.V. All rights reserved
+ *
+ * \section history Change history
+ * 20041110: M. Lauwerijssen\n Initial version
+ *
+ ********************************************************************/
+#include <stdlib.hch>
+#include "pal_master.hch"
+
+#include "configuration.hch"
+#if USE_RUNFFT
+#include "audio.hch"
+#include "fft.hch"
+
+#if HAVE_DEBUG
+ #include "debug.hch"
+#endif
+
+/*
+ * Forward declarations
+ */
+static macro expr ClockRate = PAL_ACTUAL_CLOCK_RATE;
+#if HARDWARE_MULTIPLY
+//input buffer
+ram signed 18 audio_buffer_in[256] with { block = "BlockRAM"};
+//output buffer
+ram signed 18 audio_buffer_out[128] with { block = "BlockRAM"};
+#else
+//input buffer
+ram signed 16 audio_buffer_in[256] with { block = "BlockRAM"};
+//output buffer
+ram signed 16 audio_buffer_out[128] with { block = "BlockRAM"};
+#endif
+//EQ settings for the FFT
+ram unsigned 4 EQ_info[128] with { block = "BlockRAM"};
+//EQ settings received from the display
+
+
+#if HARDWARE_MULTIPLY
+signed 18 *audioptr_in1,*audioptr_in2,*audioptr_in3,*audioptr_in4;
+
+signed 18 *audioptr_out1,*audioptr_out2;
+
+unsigned 6 *displayptr1,*displayptr2,*displayptr3,*displayptr4;
+#else
+signed 16 *audioptr_in1,*audioptr_in2,*audioptr_in3,*audioptr_in4;
+
+signed 16 *audioptr_out1,*audioptr_out2;
+
+unsigned 6 *displayptr1,*displayptr2,*displayptr3,*displayptr4;
+#endif
+
+/*! \fn macro proc audio_main(AUDIOIN, AUDIOOUT);
+ * \brief Audio I/O component main.
+ *
+ * \param audiodata Pointer to audiodata struct
+ * \param AUDIOIN Handle to audio-input
+ * \param AUDIOOUT Handle to audio-output
+ *
+ * \return Never Returns.
+ * \retval void
+ */
+macro proc audio_main(audiodata, AUDIOIN, AUDIOOUT)
+{
+ signed 18 sample;
+ unsigned 6 sample_count;
+ unsigned 8 i,cycle;
+ unsigned 4 eqinfo;
+
+ unsigned 1 FFT_Sync, first;
+ macro expr OW = PalAudioOutGetMaxDataWidthCT ();
+ macro expr IW = PalAudioInGetMaxDataWidthCT ();
+ signed LeftNew, RightNew;
+ signed Output_sample;
+
+ ram unsigned 6 input[64];
+
+ //pointers for double and quadruple buffering:
+ audioptr_in1 = &audio_buffer_in[0];
+ audioptr_in2 = &audio_buffer_in[64];
+ audioptr_in3 = &audio_buffer_in[128];
+ audioptr_in4 = &audio_buffer_in[192];
+
+ audioptr_out1 = &audio_buffer_out[0];
+ audioptr_out2 = &audio_buffer_out[64];
+
+ displayptr1 = &audiodata.ifft_info.write[0];
+ displayptr2 = &audiodata.ifft_info.write[64];
+ displayptr3 = &audiodata.ifft_info.write[128];
+ displayptr4 = &audiodata.ifft_info.write[192];
+
+ FFT_Sync=0;
+par
+{
+ for(;;)
+ {
+ if (FFT_Sync) //if 64 samples are read from ADC...
+ {
+ par
+ {
+ // switch pointers
+ audioptr_in1 = audioptr_in2;
+ audioptr_in2 = audioptr_in3;
+ audioptr_in3 = audioptr_in4;
+ audioptr_in4 = audioptr_in1;
+
+ audioptr_out1 = audioptr_out2;
+ audioptr_out2 = audioptr_out1;
+
+ displayptr1=displayptr2;
+ displayptr2=displayptr3;
+ displayptr3=displayptr4;
+ displayptr4=displayptr1;
+
+ FFT_Sync = 0;
+ }
+
+ // FFT calculation
+ perform_fft(audioptr_in1);
+
+#if PERFORM_FFT_CALCULATION
+ equalize_audio(&audiodata);
+#endif
+ // inverse FFT calculation
+ perform_ifft(audioptr_out1,displayptr1);
+ }
+ else
+ delay;
+ }
+
+ for(sample_count=0;;)//store the samples in the inputbuffer
+ {
+ if (!FFT_Sync)
+ {
+ par
+ {
+ seq
+ {
+ PalAudioInRead(AUDIOIN, &LeftNew, &RightNew);
+#if HARDWARE_MULTIPLY
+ audioptr_in1[sample_count] = LeftNew;//drop 2 LSB's
+#else
+ audioptr_in1[sample_count] = (LeftNew\\2);//drop 2 LSB's
+#endif
+ sample_count++;
+ if (!sample_count)
+ {
+ FFT_Sync = 1;
+ }
+ }
+ seq
+ {
+ Output_sample = audioptr_out2[sample_count];
+ }
+ }
+ }
+ else
+ {
+ delay;
+ }
+ }
+ for(;;)
+ {
+ PalAudioOutWrite(AUDIOOUT,(signed OW)(Output_sample @ 0),(signed OW)(Output_sample @ 0));
+ }
+}//end par
+}// end function
+#endif
+
diff --git a/Graphic_Equalizer/src/smartmedia.hcc b/Graphic_Equalizer/src/smartmedia.hcc
new file mode 100644
index 0000000..ff405c1
--- /dev/null
+++ b/Graphic_Equalizer/src/smartmedia.hcc
@@ -0,0 +1,233 @@
+/*! \file smartmedia.hcc
+ *
+ * \section generic Here we interface with the SmartMedia card.
+ *
+ * \section project Project information.
+ * Project Graphic Equalizer\n
+ * \author O.M. Schinagl
+ * \date 20041110
+ * \version 0.1
+ *
+ * \section copyright Copyright
+ * Copyright ©2004 Koninklijke Philips Electronics N.V. All rights reserved
+ *
+ * \section history Change history
+ * 20041110: O.M. Schinagl\n Initial version
+ *
+ ********************************************************************/
+
+/******** System Includes *************/
+#include <stdlib.hch>
+
+#include "pal_master.hch"
+
+/******** Application Includes ********/
+#include "configuration.hch"
+#include "display_shared.hch"
+#include "smartmedia_shared.hch"
+#include "smartmedia.hch"
+
+#if HAVE_DEBUG
+ #include "debug.hch"
+#endif
+
+#include "audio.hch"
+#include "mouse_shared.hch"
+#include "eventhandler_shared.hch"
+#include "display.hch" /* FIXME: temporary include, needs to be moved to 'init' */
+
+/*! \fn unsigned 1 smartmedia_init(void);
+ * \brief We here initialize the Smart Media card and verify wether the
+ * card is inserted and such.
+ *
+ * \return We return 0 on success, 1 on error.
+ * \retval unsigned 1
+ */
+unsigned 1 smartmedia_init(void) {
+ unsigned 1 retval;
+ /*
+ * Firstly we enable both the CPLD and the SmartMedia.
+ */
+ RC200CPLDEnable();
+ RC200SmartMediaInit(&retval);
+
+ if (retval) {
+ RC200SmartMediaReset(&retval);
+ RC200SmartMediaInit(&retval);
+ }
+
+ return retval;
+} /* --- smartmedia_init() --- */
+
+
+
+/*! \fn void smartmedia_loaddata(skindata_t *skindata);
+ * \brief We load our memory with skin and help data from the smartmedia.
+ *
+ * \param *skindata skindata like boundries and colors of elements.
+ *
+ * \return void
+ * \retval void
+ */
+void smartmedia_loaddata(skindata_t *skindata) {
+ /*
+ * Setup RAM Handle, and determin maximum Data and Address widths
+ */
+ macro expr RAM_BANK0 = PalPL2RAMCT(0);
+ macro expr DW = PalPL2RAMGetMaxDataWidthCT();
+ macro expr AW = PalPL2RAMGetMaxAddressWidthCT();
+
+ unsigned DW data;
+ unsigned 27 smartmedia_address, smartmedia_address_mask;
+ unsigned AW address;
+ unsigned 8 mask, r, g, b;
+ unsigned 3 stage;
+ unsigned 1 result;
+
+ extern ram unsigned 8 presets_default_values[768];
+
+#if HAVE_DEBUG
+ /*
+ * Print some nice stats about data loading.
+ */
+ print_eol();
+ print_hex_value(0);
+#endif
+ /*
+ * Before we enter our loop to fill our memory with valid data, we have
+ * to set the startup positions for the SmartMedia.
+ */
+ smartmedia_address = SMARTMEDIA_ADDRESS_SKIN_START;
+ smartmedia_address_mask = SMARTMEDIA_ADDRESS_SKINMASK_START;
+ stage = STAGE_LOAD_SKIN;
+ /*
+ * We start with the address of the skin, and do the loop until we have
+ * done the end of the help.
+ */
+ for (address = ADDRESS_SKIN_START; address != (ADDRESS_PRESET_RESET_END +1); address++) {
+ /*
+ * Once we are done with the loading of our skin, we need to
+ * change the smartmedia start addresses.
+ */
+ switch (address) {
+ case ADDRESS_HELP_START:
+ smartmedia_address = SMARTMEDIA_ADDRESS_HELP_START;
+ smartmedia_address_mask = SMARTMEDIA_ADDRESS_HELPMASK_START;
+ stage = STAGE_LOAD_HELP;
+ break;
+ case ADDRESS_GRAPHMASK_START:
+ smartmedia_address_mask = SMARTMEDIA_ADDRESS_GRAPHMASK_START;
+ stage = STAGE_LOAD_GRAPH;
+ break;
+ case ADDRESS_PRESET_DEMO_START:
+ smartmedia_address_mask = SMARTMEDIA_ADDRESS_PRESET_DEMO_START;
+ stage = STAGE_LOAD_PRESET;
+ break;
+ case ADDRESS_PRESET_RESET_START:
+ smartmedia_address_mask = SMARTMEDIA_ADDRESS_PRESET_RESET_START;
+ stage = STAGE_LOAD_PRESET;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Before reading our data from the smartmedia we set our
+ * address pointer to the address from our loop.
+ */
+#if HAVE_SMARTMEDIA
+ PalPL2RAMSetWriteAddress(RAM_BANK0, address);
+#else
+ PalPL2RAMSetWriteAddress(RAM_BANK0, 0);
+#endif
+
+ /*
+ * SmartMedia data is read one byte per call. Because we want
+ * to store the mask + the rgb values in one variable for later
+ * useage we need to read those 4 bytes from the smartmedia
+ * before storing it as one.
+ */
+#if HAVE_SMARTMEDIA
+ /*
+ * FIXME: Due to a bug in the DK2 smartmedia libraries we need
+ * stop reading after each byte with OperationEnd call. This is
+ * VERY slow and must be changed.
+ */
+ if ((STAGE_LOAD_SKIN == stage) || (STAGE_LOAD_HELP == stage)) {
+ RC200SmartMediaSetAddress(READ, smartmedia_address);
+ RC200SmartMediaRead(&r, TRUE);
+ RC200SmartMediaOperationEnd(&result);
+ RC200SmartMediaSetAddress(READ, (smartmedia_address +1));
+ RC200SmartMediaRead(&g, TRUE);
+ RC200SmartMediaOperationEnd(&result);
+ RC200SmartMediaSetAddress(READ, (smartmedia_address +2));
+ RC200SmartMediaRead(&b, TRUE);
+ RC200SmartMediaOperationEnd(&result);
+ }
+ RC200SmartMediaSetAddress(READ, smartmedia_address_mask);
+ RC200SmartMediaRead(&mask, TRUE);
+ RC200SmartMediaOperationEnd(&result);
+
+ switch (stage) {
+ case STAGE_LOAD_SKIN:
+ data = 0 @ mask @ r @ g @ b;
+ break;
+ case STAGE_LOAD_HELP:
+ data = 0 @ mask @ r @ g @ b;
+ break;
+ case STAGE_LOAD_GRAPH:
+ data = (unsigned DW)(0 @ mask) << 24;
+ break;
+ case STAGE_LOAD_PRESET:
+ presets_default_values[(address -ADDRESS_PRESET_DEMO_START) <- 10] = mask;
+ }
+
+#else
+ data = 0x0000ff00;
+#endif
+ /*
+ * Now that we have gathered all pixel data, store it in ram.
+ */
+ PalPL2RAMWrite(RAM_BANK0, data);
+
+#if HAVE_DEBUG
+ /*
+ * Print some nice stats about data loading.
+ */
+ if (!(address <- 10)) {
+ print_cr();
+ print_hex_value(0 @ (address \\ 11));
+ print_string(" / 000001C2 | data: ");
+ print_hex_value(data <- 32);
+ }
+#endif
+
+ /*
+ * Finally increase al our indexes approperiatly.
+ */
+ smartmedia_address += 3;
+ smartmedia_address_mask++;
+ }
+
+ /*
+ * This block needs to probably move up into the fore loop where we
+ * calculate these settings later.
+ */
+ skindata->area_spectrum_top = 200;
+ skindata->area_spectrum_bottom = 335;
+ skindata->area_spectrum_left = 77;
+ skindata->area_spectrum_right = 575;
+ skindata->area_waveform_top = 46;
+ skindata->area_waveform_bottom = 118;
+ skindata->area_waveform_left = 76;
+ skindata->area_waveform_right = 413;
+ skindata->area_volume_top = 112;
+ skindata->area_volume_bottom = 66;
+ skindata->area_volume_left = 439;
+ skindata->area_volume_right = 455;
+ skindata->color_area_volume = PIXEL_VOLUME;
+ skindata->color_area_waveform = PIXEL_WAVEFORM;
+// skindata->color_area_spectrum_top = PIXEL_SPECTRUM;
+// skindata->color_area_spectrum_bottom = PIXEL_SPECTRUM;
+ skindata->color_equalizer = PIXEL_EQUALIZER;
+} /* --- smartmedia_loaddata() --- */