Index: apps/codecs/Makefile
===================================================================
--- apps/codecs/Makefile	(revision 12960)
+++ apps/codecs/Makefile	(working copy)
@@ -48,6 +48,7 @@
 ifndef SIMVER
 $(BUILDDIR)/%.a : % $(CODECDEPS)
 
+$(OBJDIR)/mod.elf : $(OBJDIR)/mod.o
 $(OBJDIR)/wav.elf : $(OBJDIR)/wav.o
 $(OBJDIR)/sid.elf : $(OBJDIR)/sid.o
 $(OBJDIR)/adx.elf : $(OBJDIR)/adx.o
Index: apps/codecs/mod.c
===================================================================
--- apps/codecs/mod.c	(revision 0)
+++ apps/codecs/mod.c	(revision 0)
@@ -0,0 +1,958 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * MOD Codec for rockbox
+ * 
+ * Sequencer taken from Gravis Ultrasound open source mod player
+ * (forgot the name, if anyone finds out, please insert *g* )
+ * 
+ * Mixer written and ported to rockbox by Rainer Sinsch
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+ 
+ 
+ /**************
+  * This version is quite experimental and support modules up to 486kbyte, only!
+  * Source code is not cleaned and in a very untidy state
+  * Execution should however be efficient, works fine on h320
+  ******************************/
+
+ 
+#include "debug.h"
+#include "codeclib.h"
+#include <inttypes.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+
+CODEC_HEADER
+
+#define CHUNK_SIZE (1024*2)
+
+
+/* This codec supports MOD Files:
+ * 
+ */
+
+static int32_t samples[CHUNK_SIZE] IBSS_ATTR;   /* The sample buffer */
+
+static unsigned char modfile[486*1024];         /* Static buffer for module */
+static signed char *sampleMem IDATA_ATTR;                  /* Pointer to the samples */
+
+unsigned char mute[8] IDATA_ATTR;
+signed char volume[8] IDATA_ATTR;		// volume of channel
+
+int     freq[8] IDATA_ATTR;            // amiga frequency of each channel
+signed char  panval[8] IDATA_ATTR;
+int  midival[8] IDATA_ATTR;            // midi value of channel
+unsigned char lastins[8] IDATA_ATTR;            // instrument # for each channel
+int    porto[8] IDATA_ATTR;            // note to port to value
+unsigned char  portsp[8] IDATA_ATTR;            // porta speed
+unsigned char  vibspe[8] IDATA_ATTR;            // vibrato speed
+unsigned char  vibdep[8] IDATA_ATTR;            // vibrato depth
+unsigned char tremspe[8] IDATA_ATTR;            // tremolo speed
+unsigned char tremdep[8] IDATA_ATTR;            // tremolo depth
+unsigned char sinepos[8] IDATA_ATTR;            // position in sine wave
+unsigned char sineneg[8] IDATA_ATTR;            // toggle to add or subtract sine value
+unsigned char geffect[8] IDATA_ATTR;            // effect played at the time (for interface)
+
+static int freqtab[296] ICONST_ATTR = {                   // The sorted amiga table.
+    907,900,894,887,881,875,868,862,    // Finetune -8 to -1
+    856,850,844,838,832,826,820,814,    // C-1 to finetune +7
+    808,802,796,791,785,779,774,768,    // C#1 to finetune +7
+    762,757,752,746,741,736,730,725,    // D-1 to finetune +7
+    720,715,709,704,699,694,689,684,    // D#1 to finetune +7
+    678,675,670,665,660,655,651,646,    // E-1 to finetune +7
+    640,636,632,628,623,619,614,610,    // F-1 to finetune +7
+    604,601,597,592,588,584,580,575,    // F#1 to finetune +7
+    570,567,563,559,555,551,547,543,    // G-1 to finetune +7
+    538,535,532,528,524,520,516,513,    // G#1 to finetune +7
+    508,505,502,498,494,491,487,484,    // A-1 to finetune +7
+    480,477,474,470,467,463,460,457,    // A#1 to finetune +7
+    453,450,447,444,441,437,434,431,    // B-1 to finetune +7
+    428,425,422,419,416,413,410,407,    // C-2 to finetune +7
+    404,401,398,395,392,390,387,384,    // C#2 to finetune +7
+    381,379,376,373,370,368,365,363,    // D-2 to finetune +7
+    360,357,355,352,350,347,345,342,    // D#2 to finetune +7
+    339,337,335,332,330,328,325,323,    // E-2 to finetune +7
+    320,318,316,314,312,309,307,305,    // F-2 to finetune +7
+    302,300,298,296,294,292,290,288,    // F#2 to finetune +7
+    285,284,282,280,278,276,274,272,    // G-2 to finetune +7
+    269,268,266,264,262,260,258,256,    // G#2 to finetune +7
+    254,253,251,249,247,245,244,242,    // A-2 to finetune +7
+    240,238,237,235,233,232,230,228,    // A#2 to finetune +7
+    226,225,223,222,220,219,217,216,    // B-2 to finetune +7
+    214,212,211,209,208,206,205,203,    // C-3 to finetune +7
+    202,200,199,198,196,195,193,192,    // C#3 to finetune +7
+    190,189,188,187,185,184,183,181,    // D-3 to finetune +7
+    180,179,177,176,175,174,172,171,    // D#3 to finetune +7
+    170,169,167,166,165,164,163,161,    // E-3 to finetune +7
+    160,159,158,157,156,155,154,152,    // F-3 to finetune +7
+    151,150,149,148,147,146,145,144,    // F#3 to finetune +7
+    143,142,141,140,139,138,137,136,    // G-3 to finetune +7
+    135,134,133,132,131,130,129,128,    // G#3 to finetune +7
+    127,126,125,125,123,123,122,121,    // A-3 to finetune +7
+    120,119,118,118,117,116,115,114,    // A#3 to finetune +7
+    113,113,112,111,110,109,109,108,    // B-3 to finetune +7
+};
+
+// This table is for vibrato and contains half a sine wave.
+static unsigned char sintab[32] ICONST_ATTR = {
+    0, 24, 49, 74, 97,120,141,161,
+    180,197,212,224,235,244,250,253,
+    255,253,250,244,235,224,212,197,
+    180,161,141,120, 97, 74, 49, 24
+};
+
+int  speed, bpm, channels IDATA_ATTR;  // speed, bpm, channels, figure it out.
+unsigned char patdelay IDATA_ATTR;            // variable storing number of times to delay patn
+unsigned char patlooprow, patloopno IDATA_ATTR; // pattern loop variables.
+signed char row;
+char mastervol IDATA_ATTR;     // same here, current row, and master volume
+int  ord IDATA_ATTR;                   // current order being played
+bool stop;                     // flag for stop condition
+bool target[128];              // keep track positions have been targeted by loop Effect
+static unsigned char long_buf[23*31+1]; // buffer for scroll text 714
+static unsigned char short_buf[5];      // buffer for CHANNEL magic bytes
+
+// SAMPLE STRUCT
+typedef struct {
+    char name[23];			// instrument name
+    unsigned short length;            // sample length
+    signed char finetune;          // sample finetune value
+    unsigned char volume;            // sample default volume
+    unsigned short loopstart;         // sample loop start
+    unsigned short loopend;           // sample loop length
+    unsigned int offset;           // offset of sample in dram
+} Sample;
+
+// SONG STRUCT
+struct {
+    char name[20];          // song name
+    Sample inst[31];        // instrument headers
+    unsigned char songLength;        // song length
+    unsigned char numpats;           // number of physical patterns
+    unsigned char order[128];        // pattern playing orders
+} MOD;
+
+typedef struct {
+    unsigned char number;            // sample being played              5 bits
+    int period;             // frequency being played at     + 11 bits = 16.
+    unsigned char effect;            // effect number                 +  8
+    unsigned char eparm;             // effect parameter              +  8 = 4 bytes!
+} Note;
+Note *current IDATA_ATTR;
+
+static char *patbuff IDATA_ATTR;         // buffer that holds our pattern data
+static unsigned int offset IDATA_ATTR;               // offset of note in pattern data buffer.
+
+static const int iMixingRate = 44100;
+
+static int iBalance[8] IDATA_ATTR;				// Balance
+static int iFreq[8] IDATA_ATTR;				// Frequency
+static int iSamplePos[8] IDATA_ATTR;				// Position des Samplezeigers
+static int iSampleFractPos[8] IDATA_ATTR;                      // Fractal position
+static int iLoopStart[8] IDATA_ATTR;
+static int iLoopEnd[8] IDATA_ATTR;
+static int bPlayVoice[8] IDATA_ATTR;
+static int bLoopVoice[8] IDATA_ATTR;
+
+static int tick IDATA_ATTR;
+static int iSamplesPerTick IDATA_ATTR;                  // Samples Per Tick
+
+
+static inline void SetVolume(unsigned char iChannel, unsigned char iVolume)
+{
+    volume[iChannel] = iVolume;
+}
+static inline void SetBalance(int iChannel, int iVal)
+{
+    iBalance[iChannel] = iVal;
+}
+static inline void SetFreq(int iChannel, int iVal)
+{
+    iFreq[iChannel] = 3579546.471f/iVal;
+}
+static inline void PlayVoice(unsigned char iChannel, unsigned char iMode , unsigned int iBegin, unsigned int iStart, unsigned int iEnd)
+{
+    bPlayVoice[iChannel] = 1;
+    iSamplePos[iChannel] = iBegin;
+    iSampleFractPos[iChannel] = 0;
+    iLoopEnd[iChannel] = iEnd;
+	// Loopen?
+    if (iMode) {
+        bLoopVoice[iChannel] = 1;
+        iLoopStart[iChannel] = iStart;		
+    }
+    else bLoopVoice[iChannel] = false;
+}
+
+static inline void StopVoice(unsigned char iChannel)
+{
+    bPlayVoice[iChannel] = false;
+}
+
+STATICIRAM void UpdateNote(void) ICODE_ATTR;
+STATICIRAM void UpdateNote(void) {
+    unsigned char track, sample, eparmx, eparmy;
+    unsigned short soff;
+    int period;
+
+	// calculate where in the pattern buffer we should be according to
+	// the pattern number and row.
+    offset = channels*64*sizeof(Note)*MOD.order[ord]+(sizeof(Note)*row*channels);
+
+	// new row? now we loop through each channel until we have finished
+    for (track=0; track<channels; track++) {
+        current = (Note *)(patbuff+offset);	// sit our note struct at the
+											// right offset in pattn buffer
+        period = current -> period;        	// get period
+        sample = current -> number;         // get instrument #
+        eparmx = current -> eparm >> 4;     // get effect param x
+        eparmy = current -> eparm & 0xF;    // get effect param y
+
+		// for the interface, the next 3 lines just store the effect # to
+		// remember for later
+        geffect[track] = current -> effect;
+        if (geffect[track] == 0xE) geffect[track]+=2+eparmx;
+        if (current->effect == 0 && current -> eparm > 0) geffect[track] = 32;
+
+        if (sample > 0) {                   // if instrument > 0 set volume
+            lastins[track] = sample - 1;    // remember the sample #
+            volume[track] = MOD.inst[sample-1].volume;  // set chan's vol
+            SetVolume(track, volume[track]*mastervol/64);
+        }
+        if (period >= 0) {                  // if period >= 0 set freq			
+            midival[track] = period;        // remember the note
+			// if not a porta effect, then set the channels frequency to the
+			// looked up amiga value + or - any finetune			
+            if (current->effect != 0x3 && current->effect != 0x5) freq[track]=
+                        freqtab[midival[track]+MOD.inst[lastins[track]].finetune];				
+        }
+        soff = 0;                           // sample offset = nothing now
+
+        switch (current -> effect) {
+            case 0x0: break;  // dont waste my time in here!!!
+			//   0x1: not processed on tick 0
+			//   0x2: not processed on tick 0
+            case 0x3:
+                case 0x5: porto[track] = freqtab[midival[track]+MOD.inst[lastins[track]].finetune];
+                if (current -> eparm > 0 && current->effect == 0x3)
+                    portsp[track] = current -> eparm;
+                period = -1;
+                break;
+                case 0x4: if (eparmx > 0) vibspe[track] = eparmx;
+                if (eparmy > 0) vibdep[track] = eparmy;
+                break;
+			//   0x6: not processed on tick 0
+                case 0x7: if (eparmx > 0) tremspe[track] = eparmx;
+                if (eparmy > 0) tremdep[track] = eparmy;
+                break;
+                case 0x8: if (current -> eparm == 0xa4) panval[track]=7;
+                else panval[track] = (current -> eparm >> 3)-1;
+                if (panval[track] < 0) panval[track] = 0;
+                SetBalance(track, panval[track]);
+                break;			
+                case 0x9: soff = current -> eparm << 8;
+                if (soff > MOD.inst[lastins[track]].length) soff =
+                            MOD.inst[lastins[track]].length;
+                break;
+			//   0xA: processed in UpdateEffect() (tick based)
+                case 0xB: ord = current->eparm;
+                row = 0;
+                if (ord >= MOD.songLength) { ord=0; stop=true; }
+                if (target[ord]) stop=true; else target[ord]=true;
+                break;
+                case 0xC: volume[track] = current -> eparm;
+                if (volume[track] < 0)  volume[track] = 0;
+                if (volume[track] > 64) volume[track] = 64;
+                SetVolume(track, volume[track]*mastervol/64);
+                break;
+                case 0xD: row = eparmx*10 + eparmy -1;
+                if (row > 63) row =0;
+                ord++;
+                if (ord >= MOD.songLength) { ord=0; stop=true; }
+                break;
+                case 0xF: if (current->eparm < 0x20) speed = current->eparm;
+                else bpm = current->eparm;
+                break;
+                case 0xE: switch (eparmx) {
+                    case 0x1: freq[track] -= eparmy;
+                    break;
+                    case 0x2: freq[track] += eparmy;
+                    break;
+						  //   0x3: not supported (glissando)
+						  //   0x4: not supported (set vibrato waveform)
+                    case 0x5: MOD.inst[sample-1].finetune = eparmy;
+                    if (MOD.inst[sample-1].finetune > 7)
+                        MOD.inst[sample-1].finetune -= 16;
+                    break;
+                    case 0x6: if (eparmy == 0) patlooprow = row;
+                    else {
+                        if (patloopno == 0) patloopno=eparmy;
+                        else patloopno--;
+                        if (patloopno > 0) row = patlooprow-1;
+                    }
+                    break;
+						  //   0x6: not supported (set tremolo waveform)
+                    case 0x8: panval[track] = eparmy;
+                    SetBalance(track, eparmy);
+                    break;
+						  //   0x9: not processed on tick 0
+                    case 0xA: volume[track] += eparmy;
+                    if (volume[track] > 64) volume[track]=64;
+                    SetVolume(track, volume[track]*mastervol/64);
+                    break;
+                    case 0xB: volume[track] -= eparmy;
+                    if (volume[track] < 0)  volume[track]=0;
+                    SetVolume(track, volume[track]*mastervol/64);
+                    break;
+						  //   0xC: not processed on tick 0
+                    case 0xD: period = -1;
+                    break;
+                    case 0xE: patdelay = eparmy;
+                    break;
+						  //   0xF: not supported (Invert loop)
+                };
+                break;
+        };
+
+		// set the frequency on the GUS for the voice, as long as its > 0
+        if (freq[track] > 0) SetFreq(track, freq[track]);
+		// only play the note if there is a note or there is an effect 9xy
+        if (period >= 0 || soff > 0x00FF) {
+            sinepos[track]=0;                  // retrig waveform
+            sineneg[track]=0;
+			// if sample has a loop then loop it.
+            if (MOD.inst[lastins[track]].loopend > 2) PlayVoice(track, 8,
+            MOD.inst[lastins[track]].offset+soff,
+            MOD.inst[lastins[track]].offset+MOD.inst[lastins[track]].loopstart,
+            MOD.inst[lastins[track]].offset+MOD.inst[lastins[track]].loopend);
+			// else just play the sample straight and no loop.
+            else PlayVoice(track, 0,
+                           MOD.inst[lastins[track]].offset+soff,
+                           MOD.inst[lastins[track]].offset,
+                           MOD.inst[lastins[track]].offset+MOD.inst[lastins[track]].length);
+        }
+        offset += sizeof(Note);                         // increment our note pointer.
+    }
+}
+
+
+/****************************************************************************
+ *    Name : doporta                                           				*
+ * Purpose : to carry out a tone portamento to a certain note               *
+ *  Passed : -                                                              *
+ * Returns : -                                                              *
+ *  Locals : -                                                              *
+ ****************************************************************************/
+static inline void doporta(unsigned char track) {
+    if (freq[track] < porto[track]) {
+        freq[track] += portsp[track];
+        if (freq[track] > porto[track]) freq[track]=porto[track];
+    }
+    if (freq[track] > porto[track]) {
+        freq[track] -= portsp[track];
+        if (freq[track] < 1) freq[track]=1;
+        if (freq[track] < porto[track]) freq[track]=porto[track];
+    }
+    SetFreq(track, freq[track]);
+}
+
+
+/****************************************************************************
+ *    Name : dovibrato                                         			    *
+ * Purpose : to carry out a vibrato at a certain depth and speed            *
+ *  Passed : -                                                              *
+ * Returns : -                                                              *
+ *  Locals : int vib - size of delta to add or subtract from period         *
+ ****************************************************************************/
+static inline void dovibrato(unsigned char track) {
+    int vib;
+
+    vib = vibdep[track]*sintab[sinepos[track]] >> 7; // div 128
+    if (sineneg[track] == 0) SetFreq(track, freq[track]+vib);
+    else                     SetFreq(track, freq[track]-vib);
+
+    sinepos[track]+=vibspe[track];
+    if (sinepos[track] > 31) {
+        sinepos[track] -=32;
+        sineneg[track] = ~sineneg[track];		// flip pos/neg flag
+    }
+}
+
+
+/****************************************************************************
+ *    Name : dotremolo                                         			    *
+ * Purpose : to carry out a tremolo at a certain depth and speed            *
+ *  Passed : -                                                              *
+ * Returns : -                                                              *
+ *  Locals : int vib - size of delta to add or subtract from volume         *
+ ****************************************************************************/
+static inline void dotremolo(unsigned char track) {
+    int vib;
+
+    vib = tremdep[track]*sintab[sinepos[track]] >> 6; // div64
+    if (sineneg[track] == 0) {
+        if (volume[track]+vib > 64) vib = 64-volume[track];
+        SetVolume(track, (volume[track]+vib)*mastervol/64);
+    }
+    else {
+        if (volume[track]-vib < 0) vib = volume[track];
+        SetVolume(track, (volume[track]-vib)*mastervol/64);
+    }
+
+    sinepos[track]+= tremspe[track];
+    if (sinepos[track] > 31) {
+        sinepos[track] -=32;
+        sineneg[track] = ~sineneg[track];			// flip pos/neg flag
+    }
+}
+
+
+/****************************************************************************
+ *    Name : UpdateEffect                                                   *
+ * Purpose : To update any tick based effects after tick 0                  *
+ *  Passed : int tick - the actual tick number.                             *
+ * Returns : -                                                              *
+ *  Locals : int track - the number of the column/track or channel we are in*
+ *           int vib - the delta which to vibrate from the frequency with   *
+ *           byte effect - a temp variable to get the effect number wanted  *
+ *           byte eparmx - a term variable to get the effect parameter x    *
+ *           byte eparmy - a term variable to get the effect parameter y    *
+ *           static byte arpcount - a counter to tell us what to do with    *
+ *               arpeggio (we dont want to forget it too, so its static)    *
+ *           Note *current - a temporary note structure to hold the pointed *
+ *                           to note in the pattern buffer                  *
+ *    Note : To see explanations of effects check out the howto document    *
+ ****************************************************************************/
+STATICIRAM void UpdateEffect(int tick) ICODE_ATTR;
+STATICIRAM void UpdateEffect(int tick) {
+    unsigned char track, effect, eparmx, eparmy;	
+
+    if (row < 1) return;                    // if at row 0 nothing to update
+    offset -= (sizeof(Note) * channels);              // go back 4 bytes in buffer
+											// becuase update note did +4
+    for (track=0; track<channels; track++) {// start counting through tracks
+        current = (Note *)(patbuff+offset); // point our Note to right spot
+
+        effect = current -> effect;         // grab the effect number
+        eparmx = current -> eparm >> 4;     // grab the effect parameter x
+        eparmy = current -> eparm & 0xF;    // grab the effect parameter y
+
+        if (freq[track] == 0) goto skip;
+
+        switch(effect) {
+            case 0x0: if (current -> eparm > 0) {
+                switch (tick%3) {
+                    case 0: SetFreq(track, freq[track]);
+                    break;
+                    case 1: SetFreq(track, freqtab[midival[track]+(8*eparmx)+MOD.inst[lastins[track]].finetune]);
+                    break;
+                    case 2: SetFreq(track, freqtab[midival[track]+(8*eparmy)+MOD.inst[lastins[track]].finetune]);
+                    break;
+                };
+            }
+            break;
+
+            case 0x3: doporta(track);
+            break;
+
+            case 0x4: dovibrato(track);
+            break;
+
+            case 0x1: freq[track]-= current -> eparm;      	// subtract freq
+            SetFreq(track, freq[track]);
+            if (freq[track] < 54) freq[track]=54;	// stop at C-5
+            break;
+
+            case 0x2: freq[track]+= current -> eparm;
+            SetFreq(track, freq[track]);
+            break;
+
+
+            case 0x5: doporta(track);
+            volume[track] += eparmx - eparmy;
+            if (volume[track] < 0)  volume[track] = 0;
+            if (volume[track] > 64) volume[track] = 64;
+            SetVolume(track, volume[track]*mastervol/64);
+            break;
+
+            case 0x6: dovibrato(track);
+            volume[track] += eparmx - eparmy;
+            if (volume[track] < 0)  volume[track] = 0;
+            if (volume[track] > 64) volume[track] = 64;
+            SetVolume(track, volume[track]*mastervol/64);
+            break;
+
+            case 0x7: dotremolo(track);
+            break;
+
+            case 0xA: volume[track] += eparmx - eparmy;
+            if (volume[track] < 0)  volume[track] = 0;
+            if (volume[track] > 64) volume[track] = 64;
+            SetVolume(track, volume[track]*mastervol/64);
+            break;
+			case 0xE: switch(eparmx) {
+    case 0xC: if (eparmy == tick) {
+        volume[track] = 0;
+        SetVolume(track, volume[track]);
+    }
+    break;
+
+    case 0x9: if (tick % eparmy == 0) {
+        if (MOD.inst[lastins[track]].loopend > 2)
+            PlayVoice(track, 8, MOD.inst[lastins[track]].offset,
+                      MOD.inst[lastins[track]].offset+
+                              MOD.inst[lastins[track]].loopstart,
+                      MOD.inst[lastins[track]].offset+
+                              MOD.inst[lastins[track]].loopend);
+        else PlayVoice(track, 0, MOD.inst[lastins[track]].offset,
+                       MOD.inst[lastins[track]].offset,
+                       MOD.inst[lastins[track]].offset+
+                               MOD.inst[lastins[track]].length);
+    }
+    break;
+    case 0xD:	if (eparmy==tick) {
+        if (MOD.inst[lastins[track]].loopend > 2)
+            PlayVoice(track, 8, MOD.inst[lastins[track]].offset,
+                      MOD.inst[lastins[track]].offset+
+                              MOD.inst[lastins[track]].loopstart,
+                      MOD.inst[lastins[track]].offset+
+                              MOD.inst[lastins[track]].loopend);
+        else PlayVoice(track, 0, MOD.inst[lastins[track]].offset,
+                       MOD.inst[lastins[track]].offset,
+                       MOD.inst[lastins[track]].offset+
+                               MOD.inst[lastins[track]].length);
+    }
+    break;
+   };
+   break;
+        };
+skip:
+        offset+=sizeof(Note);      // increment our buffer to next note
+    }
+}
+
+STATICIRAM int LoadMODFromMem(void *pMod) ICODE_ATTR;
+STATICIRAM int LoadMODFromMem(void *pMod)
+{
+    unsigned char *part, *lbp, *ch;
+    unsigned char *pbMod = (unsigned char*)pMod;	
+    int count=0, count2=0, pattcount, period, i;
+    unsigned int gusoff, size;
+	
+	//**********************
+	//***  VERIFICATION  ***
+	//**********************	
+    part = (unsigned char*)(pbMod+1080);
+												// check what MOD format
+    if      (ci->strncasecmp((char*)part, "M.K.",4) == 0) channels = 4;
+    else if (ci->strncasecmp((char*)part, "6CHN",4) == 0) channels = 6;
+    else if (ci->strncasecmp((char*)part, "8CHN",4) == 0) channels = 8;
+    else if (ci->strncasecmp((char*)part, "FLT4",4) == 0) channels = 4;
+    else return(false);                  // not a recognized format
+
+    ci->memcpy(short_buf, part, 4);
+    short_buf[4] = '\0';
+    ci->id3->genre_string = short_buf;
+
+	//fseek(handle, 20, SEEK_SET);
+    part = (unsigned char*)(pbMod+20);
+    
+    lbp = long_buf;
+    /*********************************/
+    /***  LOAD SAMPLE INFORMATION  ***/
+    /*********************************/
+    for (count=0; count<31; count++) {          // go through 31 instruments.
+		// Sample Name
+		//fread(MOD.inst[count].name, 22, 1, handle);		
+
+		    // transfer instrument name to buffer
+        if(ci->strncasecmp(part,"st-",3)) {
+  		    ch=part;
+  		    for(i=0; (i<22) && (*ch!=0); i++,ch++) {
+  		      if((*ch==' ') && ((*(lbp-1) ==' ') || (lbp==long_buf))) continue;
+  		      if((*ch>0x1f) && (*ch<0x80) && (*ch!='#')) *lbp++ = *ch;
+  		    }
+		      if(*(lbp-1)!=' ') *lbp++ = ' ';
+  		    *lbp = 0;
+  
+        }
+
+        memcpy(MOD.inst[count].name, part, 22);
+        part+= 22;
+
+		//part[0] = fgetc(handle);                // get samples length
+		//part[1] = fgetc(handle);		
+        MOD.inst[count].length = ((part[0] * 0x100) + part[1]) * 2;
+        part+=2;
+
+		//MOD.inst[count].finetune = fgetc(handle);// get finetune
+        MOD.inst[count].finetune = *part++;		// get finetune
+				
+        if (MOD.inst[count].finetune > 7)
+            MOD.inst[count].finetune -= 16;		
+
+		//MOD.inst[count].volume = fgetc(handle); // get sample default volume
+        MOD.inst[count].volume = *part++;	// get sample default volume
+
+		// get sample loop start
+		//MOD.inst[count].loopstart = ((fgetc(handle) << 8)+fgetc(handle))*2;
+		//MOD.inst[count].loopstart = ((*part++<<8) + *part++)*2;
+        MOD.inst[count].loopstart = *part++<<8;
+        MOD.inst[count].loopstart|= *part++;
+        MOD.inst[count].loopstart<<=1;
+		
+		// get sample loop end
+		//MOD.inst[count].loopend = ((fgetc(handle) << 8)+fgetc(handle))*2 + MOD.inst[count].loopstart;
+		//MOD.inst[count].loopend = ((*part++<<8)+ *part++)*2 + MOD.inst[count].loopstart;
+        MOD.inst[count].loopend = *part++<<8;
+        MOD.inst[count].loopend|= *part++;
+        MOD.inst[count].loopend<<=1;
+        MOD.inst[count].loopend+= MOD.inst[count].loopstart;
+		
+
+		// incase the loopend is past the end of the sample fix it
+        if (MOD.inst[count].loopend > MOD.inst[count].length)
+            MOD.inst[count].loopend = MOD.inst[count].length;
+    }
+    
+    long_buf[MAX_PATH] = 0; // unfortunate limit of the scroll thread
+
+    /**************************************/
+    /***  LOAD ORDER AND SIGNATURE DATA ***/
+    /**************************************/
+    MOD.songLength = *part++;             // get number of orders.	
+    
+    if(ci->taginfo_ready) {
+      ci->id3->length = MOD.songLength*1000;
+      ci->id3->title = long_buf;
+    }  
+        
+    part++;                              // unused byte, skip it
+
+    MOD.numpats = 0;                            // highest pattern is now 0
+    for (count=0; count<128; count++) {
+        MOD.order[count] = *part++;       // get 128 orders.
+        if (MOD.order[count] > MOD.numpats)
+            MOD.numpats = MOD.order[count];     // get highest pattern.
+    }	
+    size = channels*sizeof(Note)*64*(MOD.numpats+1); // calculate buffer size
+												// try and allocate memory
+    //if (patbuff) free(patbuff);
+    if ((patbuff = (char *)codec_malloc(size)) == NULL) return(false);
+	
+	// at 1080 again, skip it	
+    part = (unsigned char*) (pbMod + 1084);
+			
+    offset =0;                                  // set buffer offset to 0
+
+    /**************************/
+    /***  LOAD PATTERN DATA ***/
+    /**************************/	
+    for (pattcount=0; pattcount <= MOD.numpats; pattcount++) {
+        for (row=0; row<64; row++) {   			// loop down through 64 notes.
+            for (count=0; count<channels; count++) {
+				// point our little note structure to patbuff
+                current = (Note *)(patbuff + offset);
+
+				// load up 4 bytes of note information from file				
+				//fread(part, 1, 4, handle);
+
+				// store sample number
+                current -> number = ((part[0] & 0xF0) + (part[2] >> 4));
+				
+				// get period
+                period = ((part[0] & 0xF) << 8) + part[1];
+				
+				// do the look up in the table against what is read in.
+				// store note (in midi style format)
+                current -> period = -1;
+                for (count2=1;count2<37; count2++) {
+                    if (period > freqtab[count2*8]-3 &&
+                        period < freqtab[count2*8]+3 )
+                        current -> period = count2*8;
+                }
+								
+				// store effects and arguments
+                current -> effect = part[2] & 0xF; 	// Effect
+                current -> eparm = part[3];        	// parameter
+				
+                offset += sizeof(Note);                  		// increment buffer pos
+                part += 4;
+            }
+        }
+    }	
+    /*************************/
+    /***  LOAD SAMPLE DATA ***/
+    /*************************/
+    gusoff =0;
+    sampleMem = (signed char*) part;
+		
+    for (count = 0; count <31; count++) {		
+        MOD.inst[count].offset = gusoff;        // get offsets in GUS memory
+        gusoff += MOD.inst[count].length;		
+    }
+    
+    tick = speed-1;
+    
+    /* Panning values = { 4,12,12, 4, 4,12,12, 4 } */
+    panval[0] = panval[3] = panval[4] = panval[7] = 4;
+    panval[1] = panval[2] = panval[5] = panval[6] = 12;
+    
+    for (count=0; count<channels; count++) {
+        SetBalance(count, panval[count]); 	// set the default panning
+        SetVolume(count, 0);       			// turn the volume right down
+		
+        PlayVoice(count, 0,0,0,0); 			// set all voices at 0
+        StopVoice(count);          			// stop all the voices.
+
+        volume[count]=0;						// clear all variables of
+        freq[count]=0;							// rubbish
+        midival[count]=0;
+        lastins[count]=0;
+        porto[count]=0;
+        portsp[count]=0;
+        vibspe[count]=0;
+        vibdep[count]=0;
+        tremspe[count]=0;
+        tremdep[count]=0;
+        sinepos[count]=0;
+        sineneg[count]=0;
+        geffect[count]=0;
+    }
+
+    speed = 6;                         // start using default speed 6
+    bpm = 125;                         // start using default BPM of 125	
+    row = 0;                           // start at row 0
+    ord = 0;                           // start at order 0	
+    stop = false;                      // no end condition yet
+    memset(target, 0, sizeof(target)); // all false
+    
+    /* Initialize basic playback variables */
+    mastervol = 64;
+    patdelay = patlooprow = patloopno = 0;
+    
+    memset(iLoopStart, 0, sizeof(iLoopStart));
+    memset(iLoopEnd, 0, sizeof(iLoopEnd));
+    memset(bPlayVoice, 0, sizeof(bPlayVoice));
+    memset(bLoopVoice, 0, sizeof(bLoopVoice));
+    
+    return(1);
+}
+
+static inline int Clip(int i)
+{
+    if (i > 32767) return(32767);
+    else if (i < -32767) return(-32767);
+    else return(i);
+}
+	
+STATICIRAM void SynthRender(void *pRenderBuffer, int iSampleCount) ICODE_ATTR;
+STATICIRAM void SynthRender(void *pRenderBuffer, int iSampleCount)
+{
+	// 125bpm entspricht 50Hz (= 0.02s)
+	// => ein tick = MixingRate/50, bzw.
+	// samples die fr einen tick vergehen: MixingRate/(bpm/2.5) = 2.5*MixingRate/bpm
+
+	//static int tick = speed-1;	
+    signed int *pLeft = (signed int *) pRenderBuffer;
+    signed int *pRight = pLeft+1;
+    signed short s;
+    int qfDistance, qfDistance2;
+		
+    int i;
+	
+    int c, Left, Right;		
+	
+    for (i=0;i<iSampleCount;i++)
+    {				
+		// Ein Tick abgelaufen?
+		//if (i%iSamplesPerTick==0)
+        if (iSamplesPerTick-- <= 0)
+        {
+            tick++;
+            if (tick >= speed) {				
+                tick = 0;                               // set the tick to nothing
+                if (row == 64) {                        // if end of pattn (64)
+                    ord++;                              // next order
+                    if (ord >= MOD.songLength) { ord=0; stop=true; }   // if end goto 1st order
+                    row = 0;                            // start at top of pattn
+                }
+
+                if (patdelay == 0) {                    // if there is no pat delay
+                    UpdateNote();          		// Update and play the note
+                    row++;                              // increment the row
+
+					/*
+                    for (int count=0;count<4;count++)					
+                    printf("I%02d V%02d N%3s     ",
+                    lastins[count]+1, volume[count], notetab[midival[count]/8]);
+						
+                    printf("\n");
+     */
+
+                }
+                else patdelay --;                       // else decrement pat delay
+            }
+            else
+                UpdateEffect(tick);                    // Else update the effects
+			
+			//iSamplesPerTick = (int) (2.5f*(float)iMixingRate/(float)bpm);
+            iSamplesPerTick = (20*iMixingRate/bpm)>>3;
+        }
+		// ab hier Puffer mischen		
+		// Alle Kan�e durchlaufen		
+        Left=0, Right=0;
+        static int iLastSample[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+								
+        for (c=0;c<channels;c++)
+        {			
+            if (bPlayVoice[c])		
+            {
+				
+				// Sample zu spielen?
+                if (iSamplePos[c] >= iLoopEnd[c])
+                {
+                    if (bLoopVoice[c]) 					
+                        iSamplePos[c] -= (iLoopEnd[c]-iLoopStart[c]);
+                    else bPlayVoice[c] = false;
+                }
+
+                if (bPlayVoice[c])
+                {
+                    s = (signed short)(sampleMem[iSamplePos[c]])*volume[c];
+						      
+                                                // Wenn die Samplefrequenz niedriger als die Mixingfrequenz ist: Interpolien
+                    if (iFreq[c] < iMixingRate) 
+                    {							
+							// Lineare Interpolation
+							//fDistance = (float)iSampleFractPos[c]/iMixingRate;
+							//fDistance2 = 1-fDistance;
+							
+                        qfDistance = iSampleFractPos[c]<<16 / iMixingRate;
+                        qfDistance2 = (1<<16)-qfDistance;
+				
+							//s = (int)(fDistance*s + fDistance2*iLastSample[c]);
+                        s = (qfDistance*s + qfDistance2*iLastSample[c])>>16;
+                    }						
+      
+						// Sample bernehmen
+                    Left += s*(16-iBalance[c])>>2;
+                    Right += s*iBalance[c]>>2;
+													
+						// Sample weiter rcken
+                    iSampleFractPos[c] += iFreq[c];
+                    while (iSampleFractPos[c] > iMixingRate) 
+                    {
+                        iSampleFractPos[c] -= iMixingRate;
+                        iSamplePos[c]++;
+														
+							// Zuletzt gespieltes Sample retten (zwecks Interpolation)
+                        iLastSample[c] = s;
+                    }
+												
+                }
+            }			
+        }
+        *pLeft = Clip(Left)<<13;
+        *pRight = Clip(Right)<<13;
+        pLeft+=2;
+        pRight+=2;		
+    }
+}
+
+enum codec_status codec_main(void)
+{
+    size_t n, bytesfree;
+    unsigned char *p;
+    unsigned int filesize;
+    int old_ord;
+
+    int bytesdone;
+
+    ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
+    ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, 1024*256);
+
+next_track:
+    if (codec_init()) {
+        return CODEC_ERROR;
+    }
+
+    while (!*ci->taginfo_ready)
+        ci->yield();
+    
+    codec_set_replaygain(ci->id3);
+
+    /* Load MOD file */    
+    p = modfile;
+    bytesfree=sizeof(modfile);
+    while ((n = ci->read_filebuf(p, bytesfree)) > 0) {
+        p += n;
+        bytesfree -= n;
+    }
+    filesize = p-modfile;
+
+    if (filesize == 0)
+        return CODEC_ERROR;
+        
+    LoadMODFromMem(modfile);
+
+    /* Make use of 44.1khz */
+    ci->configure(DSP_SET_FREQUENCY, 44100);
+    /* Sample depth is 28 bit host endian */
+    ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
+    /* Stereo output */
+    ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
+    
+    /* The main decoder loop */    
+    ci->set_elapsed(0);
+    bytesdone = 0;
+    old_ord = 0;
+    
+    while (1) {
+        ci->yield();
+        if (ci->stop_codec || ci->new_track || stop)
+            break;
+
+        if (ci->seek_time) {
+            /* New time is ready in ci->seek_time */
+            ord = ci->seek_time/1000;                      
+            row = 0;
+            ci->seek_complete();
+        }
+        
+        if(old_ord!=ord) {
+          ci->set_elapsed(ord*1000+500);
+          old_ord=ord;
+        }  
+                
+        SynthRender(samples, CHUNK_SIZE/2);
+        
+        bytesdone += CHUNK_SIZE;
+        
+        ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE/2);
+        
+    }
+
+    if (ci->request_next_track())
+        goto next_track;
+
+    return CODEC_OK;
+}
Index: apps/codecs/SOURCES
===================================================================
--- apps/codecs/SOURCES	(revision 12960)
+++ apps/codecs/SOURCES	(working copy)
@@ -11,6 +11,7 @@
 #if MEMORYSIZE > 1
 aac.c
 #endif
+mod.c
 shorten.c
 aiff.c
 speex.c
Index: apps/metadata.c
===================================================================
--- apps/metadata.c	(revision 12960)
+++ apps/metadata.c	(working copy)
@@ -1714,6 +1714,44 @@
     return true;
 }
 
+static bool get_mod_metadata(int fd, struct mp3entry* id3)
+{    
+    /* Use the trackname part of the id3 structure as a temporary buffer */
+    unsigned char buf[1084];
+    int read_bytes;
+    char *p;
+      
+
+    if ((lseek(fd, 0, SEEK_SET) < 0) 
+         || ((read_bytes = read(fd, buf, sizeof(buf))) < 1084))
+    {
+        return false;
+    }
+    
+    if ( (memcmp(&buf[1080], "M.K.", 4) != 0) &&
+         (memcmp(&buf[1080], "6CHN", 4) != 0) &&
+         (memcmp(&buf[1080], "8CHN", 4) != 0) &&
+         (memcmp(&buf[1080], "FLT4", 4) != 0) )
+    {        
+        return false; 
+    }
+
+    p = id3->id3v2buf;
+    
+    /* Copy Title as artist */
+    strcpy(p, &buf[0x00]);
+    id3->artist = p;
+    p += strlen(p)+1;
+
+    id3->bitrate = filesize(fd)/1024; /* size in kb */
+    id3->frequency = 44100;
+    id3->length = 120*1000;
+    id3->vbr = false;
+    id3->filesize = filesize(fd);
+        
+    return true;
+}
+
 /* PSID metadata info is available here: 
    http://www.unusedino.de/ec64/technical/formats/sidplay.html */
 static bool get_sid_metadata(int fd, struct mp3entry* id3)
@@ -2254,6 +2292,14 @@
 
         break;
 
+    case AFMT_MOD:
+        if (!get_mod_metadata(fd, &(track->id3)))
+        {
+            return false;
+        }
+
+        break;
+
     case AFMT_SHN:
         track->id3.vbr = true;
         track->id3.filesize = filesize(fd);
Index: apps/tree.c
===================================================================
--- apps/tree.c	(revision 12960)
+++ apps/tree.c	(working copy)
@@ -104,6 +104,7 @@
     { "m4a", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
     { "m4b", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
     { "mp4", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
+    { "mod", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
     { "shn", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
     { "aif", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
     { "aiff",TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
Index: firmware/export/id3.h
===================================================================
--- firmware/export/id3.h	(revision 12960)
+++ firmware/export/id3.h	(working copy)
@@ -47,6 +47,7 @@
     AFMT_WAVPACK,      /* WavPack */
     AFMT_ALAC,         /* Apple Lossless Audio Codec */
     AFMT_AAC,          /* Advanced Audio Coding (AAC) in M4A container */
+    AFMT_MOD,          /* MOD File Format */
     AFMT_SHN,          /* Shorten */
     AFMT_SID,          /* SID File Format */
     AFMT_ADX,          /* ADX File Format */
Index: firmware/id3.c
===================================================================
--- firmware/id3.c	(revision 12960)
+++ firmware/id3.c	(working copy)
@@ -90,6 +90,9 @@
     [AFMT_AAC] =
         AFMT_ENTRY("AAC",  "aac",     NULL,          "mp4\0"      ),
     /* Shorten */
+    [AFMT_MOD] =
+        AFMT_ENTRY("MOD",  "mod",     NULL,          "mod\0"      ),
+    /* Shorten */
     [AFMT_SHN] =
         AFMT_ENTRY("SHN",  "shorten", NULL,          "shn\0"      ),
     /* SID File Format */
