chipKIT® Development Platform

Inspired by Arduino™

SD card MOD S3M soundtrack player on PIC32

Created Sun, 20 Nov 2011 16:44:38 +0000 by serveurperso


serveurperso

Sun, 20 Nov 2011 16:44:38 +0000

Accurate MOD or S3M player with all Protracker / Scream tracker 3 effects

http://www.youtube.com/watch?v=Gg9AeQXbcFM My new FAT16/32/SDHC SDcard (FatFs) version : http://www.youtube.com/watch?v=i3Yl0TISQBE

Can read any .MOD that fit in program memory of Uno32 (128K) or Max32 (512K)

There are thousands of quality music that can be played on this code: http://modarchive.org

46KHz 11 bits with linear interpolation and stereo PWM !!! 100% integer/fixed point DSP algorithm and circular sound buffer / file system buffer.

Source code for MPIDE and MPLAB here -> http://www.serveurperso.com/temp/

Have fun:)

Pascal


svaha

Mon, 21 Nov 2011 03:06:22 +0000

Nice! I liked your Audio Spectrum Analyser as well.


serveurperso

Thu, 24 Nov 2011 23:15:00 +0000

Large code removed (zip)


zerobyte

Sun, 27 Nov 2011 14:18:25 +0000

Amazing! I tried to code a mod player on AVR XMEGA few mounths ago, it was pretty difficult especially because i used float algo to have a better sound, which finally doesnt work correctly with all mods. Can we have a look at your source code? I'm curious to see how you use the PWM as stereo DAC.

EDIT: oh sorry, It's on .pde file... weird extension. :)


serveurperso

Sun, 27 Nov 2011 15:44:59 +0000

Hi, thanks:) you don't need float, fixed point DSP and multiply before divide give very good accuracy and way better performance, If you put a 16 bit DAC on my player you get exactly the sound of any tracker with "linear interpolation" setup. I use 10 bits for mantissa (#define DIVIDER 10)

It use hardware PWM feature of PIC32 :

Setup :

 // 9 bits stereo PWM
 OpenTimer2(T2_ON | T2_PS_1_1, 512);
 OpenOC1(OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);
 OpenOC2(OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);

 // Sampler
 ConfigIntTimer3(T3_INT_ON | T3_INT_PRIOR_3);
 OpenTimer3(T3_ON | T3_PS_1_1, F_CPU / SAMPLERATE);


extern "C" {
 void __ISR(_TIMER_3_VECTOR, ipl3) T3InterruptHandler() {
  mT3ClearIntFlag();

 for(..............

..........Mixer code.............

   // Upscale to 9 bits
   out *= 2;

   // Channel volume
   out = out * Sampler.channelVolume[channel] / 64;

   // Channel panning 0 is hard left 128 is hard right
   sumL += out * min(128 - Sampler.channelPan[channel], 64) / 64;
   sumR += out * min(Sampler.channelPan[channel], 64) / 64;
  }

  // Downscale to 9 bits
  sumL /= Mod.numberOfchannels;
  sumR /= Mod.numberOfchannels;

  // Signed to unsigned
  SetDCOC1PWM(sumL + 256);
  SetDCOC2PWM(sumR + 256);
 }
}

Sorry for me english

Pascal


fulvio

Tue, 29 Nov 2011 07:12:34 +0000

This is brilliant, can't wait to give this a go and add some LCD output for song name, track length, etc. Maybe even an equalizer of sorts. Thanks a million.


serveurperso

Tue, 29 Nov 2011 07:47:15 +0000

I just finished the relationship formulas for maximum sound quality on the PIC32 hardware PWM. BITDEPTH SAMPLERATE (and DIVIDER) are adjustables and the MOD is always played at the right frequency !

#define BITDEPTH 10      // 10 bits PWM (80MHz / 1024 = 78125Hz)
#define SAMPLERATE 39063 // 78125Hz / 2
#define DIVIDER 10       // Fixed-point mantissa

// Hertz = 7093789 / (amigaPeriod * 2) for PAL
// Hertz = 7159091 / (amigaPeriod * 2) for NTSC
#define AMIGA (7093789 / 2 / SAMPLERATE << DIVIDER)
// Sampler.channelFrequency[channel] = AMIGA / amigaPeriod

fulvio

Thu, 01 Dec 2011 03:20:34 +0000

What kind of information/data can be extracted from the MOD to be displayed via an LCD?


fulvio

Thu, 01 Dec 2011 05:51:17 +0000

I have a Chipkit UNO32 running on Windows 7.

I'm getting the following error when Uploading to the board:

c:/users/fcusumano/downloads/mpide-0022-windows-20110822/hardware/pic32/compiler/pic32-tools/bin/../lib/gcc/pic32mx/4.5.1/../../../../pic32mx/bin/ld.exe: address 0xa0004418 of mod32.cpp.elf section `.stack' is not within region `kseg1_data_mem'
c:/users/fcusumano/downloads/mpide-0022-windows-20110822/hardware/pic32/compiler/pic32-tools/bin/../lib/gcc/pic32mx/4.5.1/../../../../pic32mx/bin/ld.exe: address 0xa0004800 of mod32.cpp.elf section `.ramfunc' is not within region `kseg1_data_mem'
c:/users/fcusumano/downloads/mpide-0022-windows-20110822/hardware/pic32/compiler/pic32-tools/bin/../lib/gcc/pic32mx/4.5.1/../../../../pic32mx/bin/ld.exe: Not enough space to allocate both stack and heap.  Reduce heap and/or stack size.
c:/users/fcusumano/downloads/mpide-0022-windows-20110822/hardware/pic32/compiler/pic32-tools/bin/../lib/gcc/pic32mx/4.5.1/../../../../pic32mx/bin/ld.exe: address 0xa0004418 of mod32.cpp.elf section `.stack' is not within region `kseg1_data_mem'
c:/users/fcusumano/downloads/mpide-0022-windows-20110822/hardware/pic32/compiler/pic32-tools/bin/../lib/gcc/pic32mx/4.5.1/../../../../pic32mx/bin/ld.exe: address 0xa0004800 of mod32.cpp.elf section `.ramfunc' is not within region `kseg1_data_mem'
c:/users/fcusumano/downloads/mpide-0022-windows-20110822/hardware/pic32/compiler/pic32-tools/bin/../lib/gcc/pic32mx/4.5.1/../../../../pic32mx/bin/ld.exe: Not enough space to allocate both stack and heap.  Reduce heap and/or stack size.
collect2: ld returned 1 exit status

I'm using the

NTRONIC3.MOD.h

header file.


serveurperso

Thu, 01 Dec 2011 06:55:22 +0000

Can you re download the last version ? I tested It work with Mpide 0022 20110822

(Or reduce MAXCHANNELS to 16 on older version)

Pascal


serveurperso

Thu, 01 Dec 2011 07:17:27 +0000

What kind of information/data can be extracted from the MOD to be displayed via an LCD?

Download the last version, now you have a sound buffer, inside loop you can add your own refreshLCD(); :

void loop() { fillSoundBuffer();

// You have SAMPLERATE / SOUNDBUFFERSIZE time for any custom code.

}

You can use (My English is Too poor to include in the code) :

Mod.name[20] // Raw 20 bytes from .MOD name Mod.numberOfchannels // Usually 4

Mod.length; // Number of pattern order in the song. Mod.numberOfPatterns; // Number of physical (different) pattern.

Player.orderIndex // Current pattern order (0 to Mod.length) Player.row // Current row (0 to 63)

Player.tick // Player.speed tick per Player.row (default speed is 6 like protracker) is the smallest unit of time of the MOD for inter rows effects.

Mod.order[Player.orderIndex] // Current physical pattern number...

All player logic is inside player() { ... } it is also possible and more accurate to control the LCD from here. To refresh just the information that changes, it's probably what I would do later. before I must read from SDCard

Pascal


fulvio

Thu, 01 Dec 2011 08:22:40 +0000

Can you re download the last version ? I tested It work with Mpide 0022 20110822 (Or reduce MAXCHANNELS to 16 on older version) Pascal

I'm using the latest version already of the IDE. I have an UNO32 but when I select Max32 from the Board menu it uploads just fine.

Haven't tried changing MAXCHANNELS to 16. I will try and let you know how it goes. Also what PWM output do I use for the headphones?

GND and ?

Also about displaying track information to an LCD. Would this be possible?

Something like this would be amazing:

http://www.youtube.com/watch?v=8WtwkGZnR4M&feature=youtube_gdata_player


fulvio

Thu, 01 Dec 2011 11:08:16 +0000

Got it working on my Macbook just fine using the latest MPIDE. No compile errors with Board: chipKIT UNO32 and header file: "trabalash.MOD.h".

Except, I can't actually hear the MOD playing because I'm not sure where to connect my headphone jack.

Do I connect it to PWM 13 (positive) and G (negative)? It doesn't work when I do that.

Not sure how to actually listen to the song! :oops:


serveurperso

Thu, 01 Dec 2011 12:02:17 +0000

Hi, new version of my player, please re download the entire ZIP archive (sorry). -> it display all MOD playing information inside the basic MPIDE terminal/debug window.

Plug your headphone on GND + PIN 3(left) + PIN 5 (right)

Pin3 is OC1 Pin5 is OC2


fulvio

Thu, 01 Dec 2011 12:02:35 +0000

Okay, got it working.

I had to add the following for my chipKIT UN032 to work:

setup() {
   Serial.begin(57600);
   ...
}

I then hooked up a Stereo 3.5mm headphone jack to GND and PWM 3 (left) and PWM 5 (right).


fulvio

Thu, 01 Dec 2011 12:05:29 +0000

Hi, new version of my player, please re download the entire ZIP archive (sorry). -> it display all MOD playing information inside the basic MPIDE terminal/debug window. Plug your headphone on GND + PIN 3(left) + PIN 5 (right) Pin3 is OC1 Pin5 is OC2

New version works beautifully on a UNO32. I'm waiting on my LCD to be delivered so I'll modify it to output to LCD and let you know how it goes. I'll take a video or two as well (if you don't beat me to it!) :)


fulvio

Thu, 01 Dec 2011 12:16:56 +0000

Do you know of any BIN2H converters for Mac?


serveurperso

Thu, 01 Dec 2011 12:44:57 +0000

Do you know of any BIN2H converters for Mac?

Do you have a C compiler ? Or an online php version (i can code one) or find a perl version?


serveurperso

Thu, 01 Dec 2011 16:14:48 +0000

I coded one in php on my webserver :

http://www.serveurperso.com/temp/bin2array.php (source code inside my ZIP)

Upload your mod and cut-past array data.


fulvio

Fri, 02 Dec 2011 00:30:01 +0000

I coded one in php on my webserver : http://www.serveurperso.com/temp/bin2array.php (source code inside my ZIP) Upload your mod and cut-past array data.

I wrote a ruby script that converts a binary file for use with your sketch.


fulvio

Fri, 02 Dec 2011 22:17:02 +0000

Getting the following with Board: UNO32 and the smallest MOD file "NTRONIC3.MOD.h"

/Applications/Mpide.app/Contents/Resources/Java/hardware/pic32/compiler/pic32-tools/bin/../lib/gcc/pic32mx/4.5.1/../../../../pic32mx/bin/ld: Not enough space to allocate both stack and heap.  Reduce heap and/or stack size.
collect2: ld returned 1 exit status

This was compiling fine with the old upload mod32.zip


serveurperso

Fri, 02 Dec 2011 23:25:02 +0000

lol RAM is full, just reduce the soundbuffer to 512 (now the default value) :D


fulvio

Sat, 03 Dec 2011 00:06:45 +0000

lol RAM is full, just reduce the soundbuffer to 512 (now the default value) :D

Ouch! Thought that may be the case. I think SD Card functionality needs to be implemented at some point. :)


serveurperso

Sat, 03 Dec 2011 07:56:12 +0000

.MOD with 8ch are uncommon (you have MUSHROOM.MOD in mods.zip), 16 are very very very uncommon (I never saw 16ch MOD, I have only one 32ch MOD on all my collection.),

#define MAXCHANNELS 16

it is possible to free a lot of RAM here (down to 8 or 4 ch), 90% of the ram is used by essentials arrays xxxxxxxxxx[MAXCHANNELS].


fulvio

Sun, 04 Dec 2011 11:03:03 +0000

.MOD with 8ch are uncommon (you have MUSHROOM.MOD in mods.zip), 16 are very very very uncommon (I never saw 16ch MOD, I have only one 32ch MOD on all my collection.), #define MAXCHANNELS 16 it is possible to free a lot of RAM here (down to 8 or 4 ch), 90% of the ram is used by essentials arrays xxxxxxxxxx[MAXCHANNELS].

I changed MAXCHANNELS to be 16 and now they all compile fine.

How possible is it to integrate SD card functionality? You would obviously need to have a 3.3v SD Shield that is compatible with the chipKIT series.

So far I am incredibly grateful for what you have achieved. Good on you!


serveurperso

Sun, 04 Dec 2011 18:48:04 +0000

Hi, SDCard is just SPI ... I never use shields I prefer generic 2.54 pin breakout board + F/F black/red/yellow jumper wires :)

I ordered this last week (soon at home:) http://www.dfrobot.com/index.php?route=product/product&filter_name=sd%20module&page=2&product_id=163

Pascal


amiarts

Wed, 07 Dec 2011 00:18:26 +0000

At the latest there you are with the same problem that the SD Library read only the first 32 KB of a file.

I have belonged to myself just a few old MODs. Really cool!!!

Greeting René


fulvio

Wed, 07 Dec 2011 00:44:37 +0000

At the latest there you are with the same problem that the SD Library read only the first 32 KB of a file. I have belonged to myself just a few old MODs. Really cool!!! Greeting René

You've made a good point, unfortunately that is the case for SD Card shields as well. Also with Arduino clones that have SD card functionality built onboard like this one that I have:

http://www.jaycar.com.au/productView.asp?ID=XC4216&keywords=etherten&form=KEYWORD

I wonder whether there's a way to allow more than 32KB of a file when accessed from SD.


fulvio

Wed, 07 Dec 2011 00:49:01 +0000

Hi, SDCard is just SPI ... I never use shields I prefer generic 2.54 pin breakout board + F/F black/red/yellow jumper wires :) I ordered this last week (soon at home:) http://www.dfrobot.com/index.php?route=product/product&filter_name=sd%20module&page=2&product_id=163 Pascal

Has your SDCard module arrived yet!? :)


amiarts

Wed, 07 Dec 2011 01:00:22 +0000

Nothing deals with the hardware. It is a software error which I have already described here in the forum. http://www.chipkit.org/forum/viewtopic.php?f=7&t=587


serveurperso

Wed, 07 Dec 2011 12:06:43 +0000

Hi, yes I received my two SPI SD Card reader, I would use the Microship library (if FAT32 is OK) or my own FAT16 code.

I just make another player highly optimised for S3M only (deliberately incompatible with .MOD for better pattern-streaming performances)

Playing some Purple Motion or other S3M I love it:)

...

Pascal


amiarts

Wed, 07 Dec 2011 19:40:02 +0000

S3m would be even better!!! Can you call the code of the Fat Librarys sometimes post or a link?

Greeting René


serveurperso

Wed, 07 Dec 2011 21:35:47 +0000

S3m would be even better!!! Can you call the code of the Fat Librarys sometimes post or a link? Greeting René

I need to create this code... or rip from google or :

Microchip Application Libraries :

http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2680&dDocName=en547784

http://www.schmalzhaus.com/MAL/Microchip_v2010_08_04.zip This is just the Microchip folder from the MAL

Yes S3M is better (and XM or IT is way better), but a better composer can do anything in any format; check DOPE.mod :)

Pascal


fulvio

Wed, 07 Dec 2011 23:03:08 +0000

Absolutely, dope! :ugeek:


fulvio

Fri, 09 Dec 2011 11:12:56 +0000

I wanna store these songs on my SD card! :cry:


serveurperso

Sat, 10 Dec 2011 14:24:34 +0000

I wanna store these songs on my SD card! :cry:

me too. I think the Uno32 will be too limited in RAM, large buffer size are needed for SD Card streaming for S3M, for MOD it's OK because don't need pattern unpacking.

My mini S3M engine is now accurate I uploaded on this thread -> http://www.youtube.com/watch?v=Gg9AeQXbcFM :D

I just found this for SD Card, very interesting :

http://elm-chan.org/fsw/ff/00index_e.html

PIC32MX implementation http://www.microchip.com/forums/m563218.aspx -> NBIIFS.zip work on the PIC32MX

https://www.microchip.com/forums/m572924-p2.aspx -> DMA version (better for Writes but slower for read at this time)

Edit : Now I use MPLAB and an ICD3 but NBIIFS.zip is not very complicated to run on MPIDE, it's the best SPI SD Card solution for PIC32 at this time (last FatFs version:)

Edit2 : first working version of the SD Card MOD player, MPLAB only at this time.

Pascal


serveurperso

Thu, 22 Dec 2011 23:22:00 +0000

Playing MOD or S3M from SD Card is OK but I used MPLAB for my project.

http://www.youtube.com/watch?v=i3Yl0TISQBE


fulvio

Thu, 22 Dec 2011 23:28:02 +0000

Playing MOD or S3M from SD Card is OK but I used MPLAB for my project. http://www.youtube.com/watch?v=i3Yl0TISQBE

Will this work with any compatible SD Card shield for chipKIT? Would love to see some source code and instructions on how to get it working with MPLAB.


serveurperso

Fri, 23 Dec 2011 21:28:36 +0000

Source is here : http://www.serveurperso.com/temp/ multi files MPLAB project.

Do you have a PicKit3 programmer? do you know how to reinstall your arduino-bootloader.X.Max32.hex bootloader ? (it's easy).

SPI setup is here: sdmod32/fatfs/mmcPIC32.c

/* Port Controls  (Platform dependent) */
#define CS_SETOUT() TRISFbits.TRISF12 = 0 
#define CS_LOW()  _LATF12 = 0	/* MMC CS = L */
#define CS_HIGH() _LATF12 = 1	/* MMC CS = H */
// Change the SPI port number as needed on the following 5 lines
#define SPIBRG  SPI4BRG
#define SPIBUF  SPI4BUF
#define SPISTATbits SPI4STATbits
#define SPI_CHANNEL SPI_CHANNEL4
#define SPICONbits SPI4CONbits

Update TRISFbits.TRISF12 -> SPI Chip Select pinMode (port F pin 12 to output) LATF12 -> SPI Chip Select pin (port F pin 12)

And chose the SPI port 1 / 2 / 3 / 4...

Or send me your shield datasheet I check this...

Pascal


zerobyte

Sat, 24 Dec 2011 17:49:53 +0000

Hi, thanks:) you don't need float, fixed point DSP and multiply before divide give very good accuracy and way better performance, If you put a 16 bit DAC on my player you get exactly the sound of any tracker with "linear interpolation" setup. I use 10 bits for mantissa (#define DIVIDER 10)

Ok, interesting, I'll try to replace float by fixed but Im not sure it will be better :) The main problem was the instrument player, play an instrument at specific frequency in run time is extremely long (even more on XMEGA which doesn't have euclidian div instruction, just a bull crap fraction mul instruction totally useless). How do you play instrument at specific frequency? Any tricks? Or just convert amiga period to freq, and calculate step to play it?


serveurperso

Sat, 24 Dec 2011 20:39:26 +0000

//#define SYSCLK 80000000L
#define SYSCLK 96000000L

#define BITDEPTH 11                           // 11 bits PWM
#define SAMPLERATE (SYSCLK / (1 << BITDEPTH)) // 96MHz / (1 << 11) = 46875Hz
#define SOUNDBUFFERSIZE 8192                  // Circular sound buffer
#define FATBUFFERSIZE 4096                    // File system buffers
#define DIVIDER 10                            // Fixed-point mantissa

For Protracker :

// Hz = 7093789 / (amigaPeriod * 2) for PAL
// Hz = 7159091 / (amigaPeriod * 2) for NTSC
#define AMIGA (7093789 / 2 / SAMPLERATE << DIVIDER)
// Mixer.channelFrequency[channel] = AMIGA / amigaPeriod

For Scream tracker 3 :

// Hz = 14317056 / amigaPeriod
#define AMIGA (14317056 / SAMPLERATE << DIVIDER)
// Mixer.channelFrequency[channel] = AMIGA / amigaPeriod

Note the << DIVIDER (multiplier)

And inside my mixing routine Mixer.channelSampleOffset run very fast :

Mixer.channelSampleOffset[channel] += Mixer.channelFrequency[channel];

But reals sample pointers are >> DIVIDED

samplePointer = Mixer.sampleBegin[Mixer.channelSampleNumber[channel]] +
                (Mixer.channelSampleOffset[channel] &gt;&gt; DIVIDER);

A sample reLoop is not a MODULO %, is just :

Mixer.channelSampleOffset[channel] -= Mixer.sampleLoopLength[Mixer.channelSampleNumber[channel]] &lt;&lt; DIVIDER;

Just need One euclidian div instruction by note (you can get some high speed assembly code on the web?)

this same DIVIDER is used for Linear interpolation :

out += (next - current) * (Mixer.channelSampleOffset[channel] &amp; (1 &lt;&lt; DIVIDER) - 1) &gt;&gt; DIVIDER;

!!!!!!!!!!!!!! look the compiled code you can't do faster :D ((1 << DIVIDER) - 1) as you know is not in the binary code)

Pascal


slayer1991

Thu, 19 Jan 2012 19:02:28 +0000

So can you read/write using MPIDE on FAT16?


serveurperso

Thu, 09 Feb 2012 14:24:14 +0000

So can you read/write using MPIDE on FAT16?

You need to rework a fatfs wrapper for MPIDE... It's not very complicated because the bulk of the work is already done by Aiden Morrison and Riccardo Leonardi inside mmcPIC32.c (PIC32MX512 SPI module for the generic fatfs lib)

Pascal


dosikus

Tue, 09 Feb 2016 11:43:02 +0000

The link http://www.serveurperso.com/temp/ is empty . Put please sources.


3dtech

Mon, 27 Mar 2017 11:38:58 +0000

I really enjoy working with your Basic ProtoShields. It is a means to make prototype creations (add-ons) usuable between a variety of the development boards I work with.