summaryrefslogtreecommitdiffstats
path: root/Graphic_Equalizer_v1.0/src
diff options
context:
space:
mode:
Diffstat (limited to 'Graphic_Equalizer_v1.0/src')
-rw-r--r--Graphic_Equalizer_v1.0/src/audio.hcc337
-rw-r--r--Graphic_Equalizer_v1.0/src/display.hcc475
-rw-r--r--Graphic_Equalizer_v1.0/src/eventhandler.hcc435
-rw-r--r--Graphic_Equalizer_v1.0/src/events.hcc179
-rw-r--r--Graphic_Equalizer_v1.0/src/fft.hcc513
-rw-r--r--Graphic_Equalizer_v1.0/src/main.hcc165
-rw-r--r--Graphic_Equalizer_v1.0/src/mouse.hcc131
-rw-r--r--Graphic_Equalizer_v1.0/src/runfft.hcc193
-rw-r--r--Graphic_Equalizer_v1.0/src/smartmedia.hcc393
9 files changed, 2821 insertions, 0 deletions
diff --git a/Graphic_Equalizer_v1.0/src/audio.hcc b/Graphic_Equalizer_v1.0/src/audio.hcc
new file mode 100644
index 0000000..8722ce7
--- /dev/null
+++ b/Graphic_Equalizer_v1.0/src/audio.hcc
@@ -0,0 +1,337 @@
+/*! @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
+ *
+ ********************************************************************/
+#include <stdlib.hch>
+#include "pal_master.hch"
+
+#include "configuration.hch"
+#include "smartmedia_shared.hch"
+#include "display_shared.hch"
+#if USE_RUNFFT
+#include "audio.hch"
+#include "fft.hch"
+#include "smartmedia.hch"
+#endif
+#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
+
+chan 1 event_notification;
+
+#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
+
+unsigned 1 FFT_Sync;
+signed Output_sample;
+
+/*! \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(input_source, sample_rate, AUDIOIN, AUDIOOUT) {
+ /*
+ * We simply call the appropiate handlers and pass values along.
+ * We have volume control to do this. Input and Output sampling rates
+ * are equal. We dont' need different rates.
+ */
+
+ RC200AudioInSetInput(input_source);
+ PalAudioInSetSampleRate(AUDIOIN, sample_rate);
+ PalAudioOutSetSampleRate(AUDIOOUT, sample_rate);
+} /* --- audio_init() --- */
+
+
+#if !USE_RUNFFT
+/*! /fn macro proc audio_main(audiodata, AUDIOIN, AUDIOOUT);
+ *
+ * /brief Main audiodriver. This function never returns! It copies the audio
+ * input directly to the 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);
+ PalAudioOutWrite(AUDIOOUT, (signed OW)(sample_left_in @ 0), (signed OW)(sample_right_in @ 0));
+ }
+} /* --- audio_main() --- */
+#else
+
+/*! /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)
+{
+ //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
+ {
+ run_fft(audiodata);
+ sample_audio(audiodata, AUDIOOIN);
+ output_audio(AUDIOOOUT);
+ }//end par
+} /* --- audio_main() --- */
+#endif
+
+/*! /fn macro proc run_fft(audiodata);
+ *
+ * /brief FFT loop, waits until 64 samples are read from the audio input
+ * before switching the pointers needed for double and quadruple buffering,
+ * after that sequentially calling the perform_fft, equalize_audio and
+ * perform_ifft functions.
+ *
+ * /param audiodata pointer to audio information structure.
+ *
+ * /return Never Returns.
+ * /retval void
+ */
+macro proc run_fft(audiodata)
+{
+
+ while(TRUE)
+ {
+ 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;
+ }
+} /* --- run_fft() --- */
+
+/*! /fn macro proc sample_audio(ADUIOIN);
+ *
+ * /brief Sampling loop, fills the audio input and output arrays and uses FFT_Sync
+ * to notify the FFT when 64 samples are read from the audio input.
+ *
+ * /param audiodata pointer to audio information structure.
+ *
+ * /return Never Returns.
+ * /retval void
+ */
+macro proc sample_audio(audiodata, AUDIOOIN)
+{
+ macro expr IW = PalAudioInGetMaxDataWidthCT();
+ signed IW LeftNew, RightNew;
+
+ unsigned 27 blockcount;
+ unsigned 8 not_saturated;
+ unsigned 6 sample_count;
+ unsigned 2 saturation;
+ unsigned 1 result;
+
+ par {
+ while (TRUE)
+ {
+ if (FFT_Sync && audiodata.play) //if 64 samples are read from ...
+ {
+ result = load_audio_samples(audioptr_in1, blockcount, WINDOW_SIZE);
+ if (result) {
+ blockcount = 0;
+ } else {
+ blockcount++;
+ }
+ }
+ else
+ {
+ delay;
+ }
+ }
+ while (TRUE)//store the samples in the inputbuffer
+ {
+ if (!FFT_Sync)
+ {
+ par
+ {
+ seq
+ {
+ PalAudioInRead(AUDIOIN, &LeftNew, &RightNew);
+
+ if (!audiodata.play)
+ {
+#if HARDWARE_MULTIPLY
+ audioptr_in1[sample_count] = LeftNew;
+#else
+ audioptr_in1[sample_count] = (LeftNew\\2);//drop 2 LSB's
+#endif
+ if (LeftNew > 130000) {
+ saturation++;
+ if (!saturation) {
+ audiodata.saturated = TRUE;
+ event_notification ! TRUE;
+ } else {
+ audiodata.saturated = FALSE;
+ }
+ } else {
+ not_saturated++;
+ if (!not_saturated) {
+ audiodata.saturated = FALSE;
+ saturation = 0;
+ event_notification ! TRUE;
+ }
+ }
+ }
+ sample_count++;
+ if (!sample_count)
+ {
+ FFT_Sync = TRUE;
+ }
+ }
+ seq
+ {
+ Output_sample = audioptr_out2[sample_count];
+ }
+ }
+ }
+ else
+ {
+ delay;
+ }
+ }
+ }
+}/* --- sample_audio() --- */
+
+/*! /fn macro proc output_audio(ADUIOOUT);
+ *
+ * /brief Sampling loop, fills the audio input and output arrays and uses FFT_Sync
+ * to notify the FFT when 64 samples are read from the audio input.
+ *
+ * /param audiodata pointer to audio information structure.
+ *
+ * /return Never Returns.
+ * /retval void
+ */
+macro proc output_audio(AUDIOOUT)
+{
+ macro expr OW = PalAudioOutGetMaxDataWidthCT();
+ /*
+ * Audio output loop, writes the modified audio samples to the audio output.
+ */
+ for(;;)
+ {
+ PalAudioOutWrite(AUDIOOUT,(signed OW)(Output_sample @ 0),(signed OW)(Output_sample @ 0));
+ }
+}/* --- output_audio() --- */
+
+
diff --git a/Graphic_Equalizer_v1.0/src/display.hcc b/Graphic_Equalizer_v1.0/src/display.hcc
new file mode 100644
index 0000000..81d0037
--- /dev/null
+++ b/Graphic_Equalizer_v1.0/src/display.hcc
@@ -0,0 +1,475 @@
+/*! \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;
+
+
+
+/*
+ */
+static rom unsigned 20 images[32] = {
+ ADDRESS_ABOUT_TOP_FONTYS_START,
+ ADDRESS_ABOUT_TOP_TASS_START,
+ ADDRESS_ABOUT_TOP_TRANSFER_START,
+ ADDRESS_ABOUT_TOP_CELOXICA_START,
+ ADDRESS_ABOUT_TOP_DETAILS_START,
+ ADDRESS_ABOUT_BOTTOM_START,
+ ADDRESS_SKIN_START,
+ ADDRESS_HELP_START,
+ ADDRESS_HELP_START,
+ ADDRESS_GRAPH_START
+};
+
+
+
+/*! \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
+ */
+inline 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 VISIBLEY = PalVideoOutGetVisibleY(VIDEOOUT);
+ macro expr TOTALX = PalVideoOutGetTotalX(VIDEOOUT, CLOCKRATE);
+ macro expr TOTALY = PalVideoOutGetTotalY(VIDEOOUT);
+ macro expr SCANX = PalVideoOutGetX(VIDEOOUT);
+ macro expr SCANY = PalVideoOutGetY(VIDEOOUT);
+
+ unsigned AW addresses[32];
+ unsigned DW pixeldata;
+ unsigned 24 visual_graph_color;
+ unsigned 5 address_index;
+
+
+
+ /*
+ * The passed button_state tells us if 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) {
+ PalVideoOutWrite(VIDEOOUT, ~PIXEL);
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ }
+
+ /*
+ * Prime Rendering Pipeline to start where the skin starts.
+ */
+ PalPL2RAMSetReadAddress(RAM_BANK0, images[events->image]);
+
+ /*
+ * 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, (IMAGE_GRAPH == events->image) ? (images[events->image] +(0 @ (addresses[address_index] \\ 2))) : (images[events->image] +addresses[address_index]));
+
+ /*
+ * Always reset the address_index to the corresponding
+ * array index containing the address counter of the
+ * background image, when the default skin should be
+ * displayed.
+ */
+ if (IMAGE_SKIN == events->image) {
+ address_index = MASK_AREA_BACKGROUND;
+ } else {
+ delay;
+ }
+
+ /*
+ * When displaying the visual the pixeldata read
+ * from the RAM-bank needs to be interpreted differntly,
+ * since the visual-image is not stored as a MRGB value,
+ * but as a MMMM-value. (M = mask)
+ */
+ if (IMAGE_GRAPH == events->image) {
+ par {
+ switch (addresses[MASK_AREA_BACKGROUND] <- 2) {
+ case 3:
+ 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);
+ break;
+ case 0:
+ visual_graph_color = ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[23:16]]) << 1) @ ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[23:16]]) << -1) @ ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[23:16]]) << 0);
+ break;
+ case 1:
+ visual_graph_color = ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[15:8]]) << 1) @ ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[15:8]]) << -1) @ ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[15:8]]) << 0);
+ break;
+ case 2:
+ visual_graph_color = ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[7:0]]) << 1) @ ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[7:0]]) << -1) @ ((unsigned 8)(0 @ audiodata->fft_info.read[pixeldata[7:0]]) << 0);
+ break;
+ default:
+ delay;
+ break;
+ }
+
+ 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 (MASK) {
+ /*
+ */
+ case AREA_WAVEFORM:
+ if (SCANY == 0 @ skindata->waveform.bottom -(0 @ (audiodata->ifft_info.read[((SCANX -(0 @ skindata->waveform.left)) <-8)]))) {
+ PalVideoOutWrite(VIDEOOUT, skindata->waveform.color_primary);
+ } 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->volume.color_primary);
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ break;
+
+ /*
+ * Inputgain control over the Y-axis.
+ */
+ case AREA_INPUTGAIN_YAXIS:
+ /*
+ * The inputgain_position
+ * stores the highest point of
+ * our bar. Every pixel after
+ * this point is drawn.
+ */
+ if (SCANY >= 0 @ events->inputgain_position) {
+ PalVideoOutWrite(VIDEOOUT, (events->locked_gain) ? DISABLED : (events->saturated ? skindata->inputgain.color_secondary : skindata->inputgain.color_primary));
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ break;
+
+ /*
+ * Spectrum Analyzer
+ */
+ case AREA_SPECTRUM_ANALYZER:
+ /*
+ * We draw every pixel that is smaller TODO
+ */
+ if ((SCANY >= (0 @ skindata->spectrum.bottom) -(0 @ audiodata->fft_info.read[(SCANX -(0 @ skindata->spectrum.left))[9:2]])) && ((SCANX -(0 @ skindata->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)== MASK);
+ break;
+
+ case BUTTON_PRECISE: /* fall through */
+ case BUTTON_CONVEX_HALF: /* 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) == MASK);
+ break;
+
+ case BUTTON_LOG:
+ /*
+ *
+ */
+ draw_button(audiodata->display_log);
+ break;
+
+ case BUTTON_PLAY:
+ draw_button(audiodata->play);
+ break;
+
+ case BUTTON_DEMO:
+ draw_button(events->button_demo_state);
+ break;
+ case BUTTON_RESET:
+ draw_button(events->button_reset_state);
+ break;
+
+ case BUTTON_HELP:
+ draw_button(events->image == IMAGE_HELP);
+ break;
+ case BUTTON_ABOUT:
+ draw_button(events->image == IMAGE_ABOUT);
+ break;
+
+ case AREA_ABOUT_TOP:
+ if (IMAGE_ABOUT == events->image) {
+ par {
+ events->image = events->image_about;
+ address_index = MASK_AREA_ABOUT_TOP;
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ break;
+
+ case BUTTON_URL_FONTYS: /* fall through */
+ case BUTTON_URL_TASS: /* fall through */
+ case BUTTON_URL_TRANSFER: /* fall through */
+ case BUTTON_URL_CELOXICA: /* fall through */
+ case BUTTON_URL_DETAILS: /* fall through */
+ case AREA_ABOUT_BOTTOM:
+ if (IMAGE_ABOUT == events->image) {
+ par {
+ events->image = IMAGE_ABOUT_BOTTOM;
+ address_index = MASK_AREA_ABOUT_BOTTOM;
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ break;
+
+ case AREA_MASK_END:
+ /* (IMAGE_ABOUT_TOP_FONTYS <= events->image) && (events->image <= IMAGE_ABOUT_BOTTOM)*/
+ if ((events->image <= IMAGE_ABOUT_BOTTOM) || (IMAGE_ABOUT == events->image)) {
+ par {
+ events->image = IMAGE_ABOUT;
+ address_index = MASK_AREA_BACKGROUND;
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ } else {
+ PalVideoOutWrite(VIDEOOUT, PIXEL);
+ }
+ 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:
+ /* (MASK <= AREA_EQUALIZER_MAX) && (AREA_EQUALIZER_MIN <= MASK) */
+ if ((AREA_EQUALIZER_MIN <= MASK) && (!events->locked_display)) {
+ if ((SCANY == 0 @ events->equalizer_display[(MASK -AREA_EQUALIZER_MIN) <- 7]) || ((SCANY +1) == 0 @ events->equalizer_display[(MASK -AREA_EQUALIZER_MIN) <- 7])) {
+ PalVideoOutWrite(VIDEOOUT, skindata->equalizer.color_primary);
+ } 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 = MASK;
+ 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))) {
+ par {
+ if (SCANY == (VISIBLEY +1)) {
+ par {
+ address_index++;
+ addresses[address_index] = 0;
+ }
+ } else {
+ delay;
+ }
+ /*
+ * 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.
+ */
+ par {
+ address_index = 0;
+ addresses[MASK_AREA_BACKGROUND] = 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.
+ */
+ par {
+ if (address_index != MASK_AREA_BACKGROUND) {
+ addresses[address_index]++;
+ } else {
+ delay;
+ }
+ addresses[MASK_AREA_BACKGROUND]++;
+ }
+ }
+ }
+ }
+} /* --- 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_v1.0/src/eventhandler.hcc b/Graphic_Equalizer_v1.0/src/eventhandler.hcc
new file mode 100644
index 0000000..baa5969
--- /dev/null
+++ b/Graphic_Equalizer_v1.0/src/eventhandler.hcc
@@ -0,0 +1,435 @@
+/*! \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 "display_shared.hch"
+#include "eventhandler.hch"
+#include "events.hch"
+#include "display.hch"
+
+#if HAVE_DEBUG
+ #include "debug.hch"
+#endif
+
+
+
+/*
+ */
+extern chan unsigned 1 maskupdate_notification;
+extern chan unsigned 1 event_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
+ */
+inline void eventhandler_main(audiodata_t *audiodata, events_t *events, mousedata_t *mousedata, skindata_t *skindata) {
+ mpram {
+ ram unsigned 4 write[768];
+ rom unsigned 4 read[768];
+ } equalizer_levels with { block = "BlockRAM"};
+
+ unsigned 11 reference_point, reference_point_right;
+ unsigned 10 preset_offset;
+ unsigned 6 gain_counter;
+ unsigned 5 old_volume;
+ unsigned 5 volume;
+ unsigned 4 gain;
+ unsigned 4 index_offset, index_end;
+ unsigned 4 equalizer_mode_local;
+ unsigned 1 newmaskupdate, eventupdate;
+
+ audiodata->display_log = TRUE;
+ audiodata->play = FALSE;
+ events->image = IMAGE_SKIN;
+ events->button_demo_state = FALSE;
+ events->button_reset_state = FALSE;
+ events->saturated = FALSE;
+
+ volume = change_volume_from_coordinate(volumecontrol_table_inv[0x18], events, skindata);
+ gain = change_inputgain_from_coordinate(inputgain_table_inv[0xf], events, skindata);
+ load_preset(LOAD_PRESET_RESET, equalizer_levels.write);
+ reload_equalizer(events, &equalizer_levels.write[preset_offset]);
+
+ par {
+ while (TRUE) {
+ event_notification ? eventupdate;
+
+ if (audiodata->saturated) {
+ gain_counter--;
+ if (!gain_counter) {
+ gain--;
+ change_inputgain_from_coordinate(inputgain_table_inv[gain], events, skindata);
+ events->saturated = TRUE;
+ }
+ }
+ }
+ 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 (IMAGE_GRAPH == events->image) {
+ events->image = IMAGE_SKIN;
+ events->mask = 0;
+ } else {
+ delay;
+ }
+
+ /*
+ */
+ if (BUTTON_MODE == events->mask) {
+ if (IMAGE_GRAPH == events->image) {
+ events->image = IMAGE_SKIN;
+ } else {
+ events->image = IMAGE_GRAPH;
+ }
+ } else {
+ delay;
+ }
+
+ /*
+ * If the current mask equals the help button
+ * we set display mode to help.
+ */
+ if ((IMAGE_ABOUT != events->image) && (BUTTON_HELP == events->mask)) {
+ /*
+ * Change the mode to help if it's
+ * currently not set, otherwise go back
+ * to skin mode.
+ */
+ if (IMAGE_HELP == events->image) {
+ events->image = IMAGE_SKIN;
+ } else {
+ events->image = IMAGE_HELP;
+ }
+ } else {
+ delay;
+ }
+
+ if ((IMAGE_HELP != events->image) && (BUTTON_ABOUT == events->mask)) {
+ /*
+ * Change the mode to about if it's
+ * currently not set, otherwise go back
+ * to skin mode.
+ */
+ if (IMAGE_ABOUT == events->image) {
+ events->image = IMAGE_SKIN;
+ } else {
+ events->image_about = IMAGE_ABOUT_TOP_TASS;
+ events->image = IMAGE_ABOUT;
+ }
+ } else {
+ delay;
+ }
+
+ if (BUTTON_EXIT_TO_SKIN == events->mask) {
+ /*
+ */
+ events->image = IMAGE_SKIN;
+ } else {
+ delay;
+ }
+
+ /*
+ */
+ if ((BUTTON_URL_FONTYS <= events->mask) && (events->mask <= BUTTON_URL_DETAILS)) {
+ events->image_about = (events->mask -BUTTON_URL_FONTYS) <- 5;
+ } 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]; /*
+ * Reload the equalizer bars
+ * from our buffer into
+ * the display memory.
+ */
+ 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) {
+ events->button_demo_state = TRUE;
+ 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) {
+ events->button_reset_state = TRUE;
+ 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;
+ }
+
+ if (BUTTON_PLAY == events->mask) {
+ audiodata->play = !audiodata->play;
+ if (audiodata->play) {
+ events->locked_gain = TRUE;
+ } else {
+ events->locked_gain = FALSE;
+ }
+ } else {
+ delay;
+ }
+
+
+/*
+ if ((BUTTON_PAUSE == events->mask) && (audiodata->player != STOP_AUDIO)) {
+ if (PLAY_AUDIO == audiodata->player) {
+ audiodata->player = PAUSE_AUDIO;
+ } else {
+ audioplay->player = RESUME_AUDIO;
+ }
+ } else {
+ delay;
+ }
+
+ if (BUTTON_PLAY == events->mask) {
+ if (PAUSE_AUDIO == audiodata->player) {
+ audioplay->player = RESUME_AUDIO;
+ } else {
+ old_volume = volume;
+ change_volume_from_coordinate(volulmecontrol_table_inv[0x18], events, skindata);
+ audiodata->player = PLAY_AUDIO;
+ }
+ } else {
+ delay;
+ }
+
+ if (BUTTON_STOP == events->mask) {
+ audiodata->player = STOP_AUDIO;
+ volume = change_volume_from_coordinate(volulmecontrol_table_inv[old_volume], events, skindata);
+ } 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) {
+ /*
+ * Change the volume depending
+ * on the y position.
+ */
+ volume = change_volume_from_coordinate(mousedata->y, events, skindata);
+ } else {
+ delay;
+ }
+
+ if ((AREA_INPUTGAIN_YAXIS == events->mask) && (!events->locked_gain)) {
+ /*
+ * Change the inputgain
+ * depending on the y position.
+ * We store the 'set' gain to
+ * be used with the automatic
+ * input gain detection.
+ */
+ gain = change_inputgain_from_coordinate(mousedata->y, events, skindata);
+ /*
+ * We manually update the
+ * inputgain so we change the
+ * color of the slider.
+ */
+ events->saturated = FALSE;
+ } 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) <- 10];
+ events->equalizer_display[(events->mask -AREA_EQUALIZER_MIN) <- 7] = 0 @ (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 11 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) <- 10];
+ events->equalizer_display[equalizer_index] = average_bar;
+ events->locked_display = FALSE;
+ }
+ }
+ } else {
+ delay;
+ }
+
+ if (BUTTON_DEMO != events->mask) {
+ events->button_demo_state = FALSE;
+ }
+ if (BUTTON_RESET != events->mask) {
+ events->button_reset_state = FALSE;
+ }
+
+ break;
+
+ case MOUSE_STATE_ON_RELEASE:
+ events->button_demo_state = FALSE;
+ events->button_reset_state = FALSE;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+} /* --- eventhandler_main() --- */
+
+
+
+/*
+ * Volume Control lookuptable.
+ * TODO: This table is now hardcoded. To ensure full skinability this table
+ * should be dynamically loaded.
+ */
+ram 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};
+ram unsigned 11 volumecontrol_table_inv[32] = {111, 110, 108, 106, 105, 103, 102, 100, 99, 97, 96, 94, 93, 91, 90, 88, 87, 85, 84, 82, 81, 79, 78, 76, 75, 73, 72, 70, 69, 67, 66};
+
+ram unsigned 4 inputgain_table[46] = {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, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0};
+ram unsigned 11 inputgain_table_inv[16] = {111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81, 78, 75, 72, 69, 66};
diff --git a/Graphic_Equalizer_v1.0/src/events.hcc b/Graphic_Equalizer_v1.0/src/events.hcc
new file mode 100644
index 0000000..275bc25
--- /dev/null
+++ b/Graphic_Equalizer_v1.0/src/events.hcc
@@ -0,0 +1,179 @@
+/*! \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 "display_shared.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 set_preset(unsigned 10 *active_preset,
+ * unsigned 10 *preset_offset, unsigned 8 new_preset,
+ * unsigned 4 *equalizer_levels_ptr,
+ * unsigned 4 *equalizer_levels)
+ * \brief This function changes the active preset to the new_preset
+ * received from the userinterface and updates internal pointers.
+ *
+ * \param *active_preset Local store that holds the current
+ * active preset.
+ * \param *preset_offset Local store that holds the index to the
+ * current active preset in the presets
+ * array.
+ * \param new_preset The new preset.
+ * \param *equalizer_levels_ptr Pointer pointing to the current
+ * equalizer settings.
+ * \param *equalizer_levels Local store with all presets.
+ */
+inline void set_preset(unsigned 10 *active_preset, unsigned 10 *preset_offset, unsigned 8 new_preset, unsigned 4 *equalizer_levels_ptr, unsigned 4 *equalizer_levels) {
+ /*
+ * The active preset is determined by the mask minus an offset. Hence
+ * ranging our active preset from 0 to 6.
+ */
+ *active_preset = 0 @ new_preset;
+ /*
+ * 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 = *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.
+ */
+ equalizer_levels_ptr = &equalizer_levels[*preset_offset];
+}
+
+
+
+/*
+ */
+inline unsigned 5 change_volume_from_coordinate(unsigned 11 coordinate, events_t *events, skindata_t *skindata) {
+ unsigned 5 retval;
+ unsigned 5 volumeleft;
+
+ /*
+ * Copy the current Y cursor position to the events struct. This we
+ * need for drawing purposes.
+ */
+ events->volume_position = coordinate;
+ /*
+ * 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.
+ */
+ volumeleft = volumecontrol_table[(coordinate -skindata->volume.top) <- 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(!volumeleft, (0x1f -volumeleft), (0x1f -volumeleft));
+ /*
+ * Now that we have set the gain, we return it incase someone needs it.
+ */
+ retval = volumeleft;
+
+ return retval;
+}
+
+
+
+/*
+ */
+inline unsigned 4 change_inputgain_from_coordinate(unsigned 11 coordinate, events_t *events, skindata_t *skindata) {
+ unsigned 4 retval;
+ unsigned 4 gainleft;
+
+ /*
+ * Copy the current Y cursor position to the events struct. This we
+ * then later use for drawing purposes.
+ */
+ events->inputgain_position = coordinate;
+ /*
+ * Look the relative y-coordinate up in the inputgain lookup table. We
+ * make a local copy here because the RC200 call doesn't behave nicely
+ * when passing anything else.
+ */
+ gainleft = inputgain_table[(coordinate -skindata->inputgain.top) <- 6];
+ /*
+ * Finally we set the gain as calculated.
+ */
+ RC200AudioInSetGain(!gainleft, gainleft, gainleft);
+ /*
+ * Now that we have set the gain, we return it incase someone needs it.
+ */
+ retval = gainleft;
+
+ return retval;
+}
+
+
+
+/*! \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 11 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_v1.0/src/fft.hcc b/Graphic_Equalizer_v1.0/src/fft.hcc
new file mode 100644
index 0000000..81098c0
--- /dev/null
+++ b/Graphic_Equalizer_v1.0/src/fft.hcc
@@ -0,0 +1,513 @@
+/*! \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"};
+
+mpram
+{
+ ram signed 18 rwrite[256];
+ rom signed 18 read[256];
+} imaginary with {block = "BlockRAM"};
+#else
+mpram
+{
+ ram signed 24 rwrite[256];
+ rom signed 24 read[256];
+} real with {block = "BlockRAM"};
+
+mpram
+{
+ ram signed 24 rwrite[256];
+ rom signed 24 read[256];
+} imaginary with {block = "BlockRAM"};
+#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 ARRAY MUST BE DONE IN
+ * 2 STEPS. FIRST THE VALUES HAVE TO BE 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.
+ */
+ /* Copy array values to separate variables */
+ par
+ {
+ p = real.read[point1];
+ q = imaginary.read[point1];
+ }
+ par
+ {
+ r = real.read[point2];
+ t = imaginary.read[point2];
+ }
+ /* Copy variables back to their new positions */
+ 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;
+ }
+ //Bitreversing end
+}
+
+/*! \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;
+
+ //initialize variables before the copying pipeline
+#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
+ // 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.
+ //Because the display routine needs unsigned values a cast is done here, this should be fixed
+ //in such a way a cast is not necessary anymore.
+ 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;
+
+ //Write data to FFT_info array to be displayed as a sound spectrum
+ audiodata->fft_info.write[0 @ (i <- 7)] = (old_value <= (tmp<-7)) ? (tmp<-7) : old_value-1;
+ }
+ else
+ {
+ //Write data to FFT_info array to be displayed as a sound spectrum
+
+ 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_v1.0/src/main.hcc b/Graphic_Equalizer_v1.0/src/main.hcc
new file mode 100644
index 0000000..48ef036
--- /dev/null
+++ b/Graphic_Equalizer_v1.0/src/main.hcc
@@ -0,0 +1,165 @@
+/*! \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 "eventhandler_shared.hch"
+#include "display_shared.hch"
+#include "mouse.hch"
+#include "eventhandler.hch"
+#include "display.hch"
+#include "smartmedia.hch"
+
+#include "fft.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 AUDIOINITWIDTH audioinitdelay;
+ unsigned 1 result;
+
+ audioinitdelay = AUDIOINITDELAY;
+
+ while (audioinitdelay) {
+ audioinitdelay--;
+ }
+
+ /*
+ * 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);
+ PalPL2RAMRequire(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);
+
+ /*
+ * The smartmedia device needs the CPLD to run also.
+ */
+ CPLDRun(ClockRate);
+ SmartMediaRun(ClockRate);
+#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_eol();
+ print_string("Graphic Equalizer 2");
+ print_eol();
+#endif
+ PalVideoOutEnable(VideoOut);
+ PalAudioInEnable(AudioIn);
+ PalAudioOutEnable(AudioOut);
+ audio_init(LINE_IN, SR_44100, AudioIn, AudioOut);
+
+ /*
+ * Once we properly setup the SmartMedia we load our
+ * data folowed by our main program loop.
+ */
+ result = smartmedia_init();
+ if (!result) {
+ 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, &skindata);
+ audio_main(audiodata, AudioIn, AudioOut);
+ }
+ } else {
+#if HAVE_DEBUG
+ print_string("Error Initializing SmartMedia");
+#endif
+ }
+ }
+ }
+
+} /* --- main() --- */
diff --git a/Graphic_Equalizer_v1.0/src/mouse.hcc b/Graphic_Equalizer_v1.0/src/mouse.hcc
new file mode 100644
index 0000000..84c324f
--- /dev/null
+++ b/Graphic_Equalizer_v1.0/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
+ */
+inline 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 = 0 @ 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_v1.0/src/runfft.hcc b/Graphic_Equalizer_v1.0/src/runfft.hcc
new file mode 100644
index 0000000..7098070
--- /dev/null
+++ b/Graphic_Equalizer_v1.0/src/runfft.hcc
@@ -0,0 +1,193 @@
+/*! \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
+{
+ /*
+ * FFT loop, waits until 64 samples are read from the audio input
+ * before switching the pointers needed for double and quadruple buffering, after that
+ * sequentially calling the perform_fft, equalize_audio and perform_ifft functions.
+ */
+ 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;
+ }
+ /*
+ * Sampling loop, fills the audio input and output arrays and uses FFT_Sync
+ * to notify the FFT when 64 samples are read from the audio input.
+ */
+ 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;
+#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;
+ }
+ }
+ /*
+ * Audio output loop, writes the modified audio samples to the audio output.
+ */
+ for(;;)
+ {
+ PalAudioOutWrite(AUDIOOUT,(signed OW)(Output_sample @ 0),(signed OW)(Output_sample @ 0));
+ }
+}//end par
+}// end function
+#endif
+
diff --git a/Graphic_Equalizer_v1.0/src/smartmedia.hcc b/Graphic_Equalizer_v1.0/src/smartmedia.hcc
new file mode 100644
index 0000000..f02b8bc
--- /dev/null
+++ b/Graphic_Equalizer_v1.0/src/smartmedia.hcc
@@ -0,0 +1,393 @@
+/*! \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' */
+
+
+unsigned 1 physical_format;
+
+/*! \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
+ */
+inline unsigned 1 smartmedia_init(void) {
+ unsigned 1 retval;
+ /*
+ * Firstly we enable both the CPLD.
+ */
+ RC200CPLDEnable();
+
+ /*
+ * We must reset the Smart Media before initializing it. If we don't reset it
+ * we get a lot of Init failures. If we don't use the delay, we get a lot of
+ * init failures.
+ */
+ RC200SmartMediaReset(&retval);
+ delay;
+ RC200SmartMediaInit(&retval);
+
+
+ /*
+ * Before we enter our main Smart Media read loop we verify the format
+ * of the SMC. This to ensure we use the correct functions later.
+ */
+ RC200SmartMediaCheckLogicalFormat(&physical_format);
+
+ 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
+ *
+ * FIXME: Currently we set the Ram handle here and in the main. If we
+ * would want to change it here, also change it elsewhere. A better
+ * solution would be to have the RAM_BANK0 macro defined somewhere
+ * globally.
+ */
+ macro expr RAM_BANK0 = PalPL2RAMCT(0);
+ macro expr DW = PalPL2RAMGetMaxDataWidthCT();
+ macro expr AW = PalPL2RAMGetMaxAddressWidthCT();
+
+ unsigned DW data;
+ unsigned 27 sm_address;
+ unsigned AW address, address_end;
+ unsigned 8 mask, r, g, b;
+ unsigned 4 stage;
+ unsigned 1 result;
+
+ extern ram unsigned 8 presets_default_values[768];
+
+ /*
+ * We have several stages to go through. We stop once we pass the last
+ * one.
+ */
+ while ((STAGE_LOAD_ABOUT_BOTTOM +1) != stage) {
+ /*
+ * For each iteration of the main loop we set a different
+ * start and end variables.
+ */
+ switch (stage) {
+ case STAGE_LOAD_DEMO_PRESET:
+ sm_address = SMARTMEDIA_ADDRESS_PRESET_DEMO_START;
+ address = INDEX_PRESET_DEMO_START;
+ address_end = INDEX_PRESET_DEMO_END;
+ break;
+ case STAGE_LOAD_RESET_PRESET:
+ sm_address = SMARTMEDIA_ADDRESS_PRESET_RESET_START;
+ address = INDEX_PRESET_RESET_START;
+ address_end = INDEX_PRESET_RESET_END;
+ break;
+ case STAGE_LOAD_SKIN:
+ sm_address = SMARTMEDIA_ADDRESS_SKIN_START;
+ address = ADDRESS_SKIN_START;
+ address_end = ADDRESS_SKIN_END;
+ break;
+ case STAGE_LOAD_HELP:
+ sm_address = SMARTMEDIA_ADDRESS_HELP_START;
+ address = ADDRESS_HELP_START;
+ address_end = ADDRESS_HELP_END;
+ break;
+ case STAGE_LOAD_GRAPH:
+ sm_address = SMARTMEDIA_ADDRESS_GRAPH_START;
+ address = ADDRESS_GRAPH_START;
+ address_end = ADDRESS_GRAPH_END;
+ break;
+ case STAGE_LOAD_TOP_FONTYS:
+ sm_address = SMARTMEDIA_ADDRESS_TOP_FONTYS_START;
+ address = ADDRESS_ABOUT_TOP_FONTYS_START;
+ address_end = ADDRESS_ABOUT_TOP_FONTYS_END;
+ break;
+ case STAGE_LOAD_TOP_TASS:
+ sm_address = SMARTMEDIA_ADDRESS_TOP_TASS_START;
+ address = ADDRESS_ABOUT_TOP_TASS_START;
+ address_end = ADDRESS_ABOUT_TOP_TASS_END;
+ break;
+ case STAGE_LOAD_TOP_TRANSFER:
+ sm_address = SMARTMEDIA_ADDRESS_TOP_TRANSFER_START;
+ address = ADDRESS_ABOUT_TOP_TRANSFER_START;
+ address_end = ADDRESS_ABOUT_TOP_TRANSFER_END;
+ break;
+ case STAGE_LOAD_TOP_CELOXICA:
+ sm_address = SMARTMEDIA_ADDRESS_TOP_CELOXICA_START;
+ address = ADDRESS_ABOUT_TOP_CELOXICA_START;
+ address_end = ADDRESS_ABOUT_TOP_CELOXICA_END;
+ break;
+/*
+ case STAGE_LOAD_TOP_DETAILS:
+ sm_address = SMARTMEDIA_ADDRESS_TOP_DETAILS_START;
+ address = ADDRESS_ABOUT_TOP_DETAILS_START;
+ address_end = ADDRESS_ABOUT_TOP_DETAILS_END;
+ break;
+*/
+ case STAGE_LOAD_ABOUT_BOTTOM:
+ sm_address = SMARTMEDIA_ADDRESS_BOTTOM_START;
+ address = ADDRESS_ABOUT_BOTTOM_START;
+ address_end = ADDRESS_ABOUT_BOTTOM_END;
+ break;
+ default:
+ break;
+ }
+ /*
+ * TODO: Replace the above switch-case with a lookuptables.
+ */
+
+ /*
+ * The only difference between logical and phyiscally formated
+ * SMCs codewise is how they are addressed.
+ */
+ if (physical_format) {
+ RC200SmartMediaSetAddress(READ, sm_address);
+ } else {
+ RC200SmartMediaSetLogicalAddress(READ, sm_address);
+ }
+
+ /*
+ * While the address hasn't reached the end, continue loading data.
+ */
+ while (address != address_end) {
+
+ /*
+ * No matter what we read from the SMC, we aways need to
+ * read at least one byte per iteration. (Otherwise there
+ * would be no point in entering this loop.
+ */
+ RC200SmartMediaRead(&mask, FALSE);
+
+ /*
+ * The difference when loading data from the SMC is
+ * when we load the presets. These aren't stored in
+ * external RAM but in an array on the FPGA.
+ */
+ if ((STAGE_LOAD_DEMO_PRESET == stage) || (STAGE_LOAD_RESET_PRESET == stage)) {
+ /*
+ * We only read one byte from the SMC and thus
+ * we only store one byte. We re-use the 'mask'
+ * variable here. The address is also re-used
+ * and thus we only use the last 10 bits to fit
+ * the address in our index.
+ *
+ */
+ presets_default_values[address <- 10] = mask;
+ } else {
+ /*
+ * All other data has RGB image data and thus
+ * we read those additional bytes from the SMC.
+ * The image used for the graphic visualization
+ * is packed together however and thus we
+ * re-use the rgb variables here.
+ */
+ RC200SmartMediaRead(&r, FALSE);
+ RC200SmartMediaRead(&g, FALSE);
+ RC200SmartMediaRead(&b, FALSE);
+
+ /*
+ * There needs to be atleast one clock cycle
+ * between setting the address and reading
+ * from it. We therefore set the address before
+ * reading from the SmartMedia as 'delay'.
+ */
+ PalPL2RAMSetWriteAddress(RAM_BANK0, address);
+
+ /*
+ * FIXME: Do we need this even?
+ */
+ data = 0 @ mask @ r @ g @ b;
+
+ /*
+ * Now that we read a while 32bit wide word
+ * we can store it in the main memory bank.
+ */
+ PalPL2RAMWrite(RAM_BANK0, data);
+ }
+
+#if HAVE_DEBUG
+ /*
+ * Print some indication about data loading.
+ */
+ if (!(address <- 14)) {;
+ print_string(".");
+ }
+#endif
+ /*
+ * Finally we increase our address to prepare for the
+ * next iteration.
+ */
+ address++;
+ }
+ /*
+ * We need to tell the SmartMedia that the last byte was read
+ * however to check wether it is the last byte during each
+ * iteration of the loop would unecasserly 'a lot' of
+ * resources. We therefore read a dummy byte here. It doesn't
+ * matter where it comes from (from the SMC) as we don't use
+ * it.
+ */
+ RC200SmartMediaRead(&mask, TRUE);
+ /*
+ * Because we need to set a new starting address in the next
+ * iteration we need to 'end' the SmartMedia Operation.
+ */
+ RC200SmartMediaOperationEnd(&result);
+
+ /*
+ * We are done with this 'stage' and continue to the next one.
+ */
+ stage++;
+ }
+
+ /*
+ * TODO: This block needs to move up into the loop where we calculate
+ * these settings determind by the image data.
+ */
+ skindata->spectrum.top = 200;
+ skindata->spectrum.bottom = 335;
+ skindata->spectrum.left = 77;
+ skindata->spectrum.right = 575;
+// skindata->spectrum.color_primary = PIXEL_SPECTRUM;
+// skindata->spectrum.color_secondary = PIXEL_SPECTRUM;
+
+ skindata->waveform.top = 46;
+ skindata->waveform.bottom = 118;
+ skindata->waveform.left = 76;
+ skindata->waveform.right = 413;
+ skindata->waveform.color_primary = PIXEL_WAVEFORM;
+
+ skindata->volume.top = 66;
+ skindata->volume.bottom = 112;
+ skindata->volume.left = 431;
+ skindata->volume.right = 448;
+ skindata->volume.color_primary = PIXEL_VOLUME;
+
+ skindata->inputgain.top = 66;
+ skindata->inputgain.bottom = 112;
+ skindata->inputgain.left = 450;
+ skindata->inputgain.right = 467;
+ skindata->inputgain.color_primary = PIXEL_INPUTGAIN_NORM;
+ skindata->inputgain.color_secondary = PIXEL_INPUTGAIN_SAT;
+
+ skindata->equalizer.color_primary = PIXEL_EQUALIZER;
+} /* --- smartmedia_loaddata() --- */
+
+/*
+smartmedia_load_block() {
+
+ setaddress();
+ for () {
+ smart_read();
+ }
+ end();
+}*/
+
+
+unsigned 1 load_audio_samples(signed 18 *samples, unsigned 27 blockoffset, unsigned 7 sample_count) {
+ ram unsigned 8 data[128];
+
+ unsigned 16 sampleword;
+ unsigned 8 sampleindex, samplebyte, samplecount;
+ unsigned 1 result;
+ unsigned 1 retval;
+
+ samplecount = (0 @ sample_count) <<1;
+ sampleindex = 0;
+ retval = 0;
+
+ if (!blockoffset) {
+ smartmedia_set_read_address(SMARTMEDIA_ADDRESS_AUDIO_START)
+ }
+
+ smartmedia_read_bytes(data, samplecount);
+
+ while (sampleindex != samplecount) {
+ samplebyte = data[sampleindex <- 7];
+ sampleword = samplebyte @ data[(sampleindex +1) <- 7];
+ samples[sampleindex >>1] = (signed 18)(sampleword @ 0);
+ sampleindex +=2;
+ }
+
+ if (((blockoffset <<7) +(0 @ samplecount) +SMARTMEDIA_ADDRESS_AUDIO_START) >= SMARTMEDIA_ADDRESS_AUDIO_END) {
+ retval = 1;
+ }
+ return retval;
+}
+
+void smartmedia_set_read_address(unsigned 20 address)
+{
+ unsigned 8 dummy;
+ unsigned 1 result;
+
+ /*
+ * Read dummy value to signal the SmartMedia card reader
+ * that the last byte is read from the SmartMedia card
+ */
+ RC200SmartMediaRead(&dummy, TRUE);
+ RC200SmartMediaOperationEnd(&result);
+ /*
+ * Check the format of the SmartMedia card and set the address accordingly
+ */
+ if (physical_format)
+ {
+ RC200SmartMediaSetAddress(READ, address);
+ } else {
+ RC200SmartMediaSetLogicalAddress(READ, address);
+ }
+}
+
+void smartmedia_read_bytes(unsigned 8 *data, unsigned 8 bytecount)
+{
+ unsigned 8 byteindex;
+ unsigned 8 temp;
+
+ byteindex = 0;
+ while (byteindex != bytecount) {
+ RC200SmartMediaRead(&temp, FALSE);
+ data[byteindex] = temp;
+ byteindex++;
+ }
+}