PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HWSound.cpp Source File

HWSound.cpp

Go to the documentation of this file.
00001 /**************************************************************************/
00002 /*!
00003     @file     HWSound.cpp
00004     @author   Jonne Valola
00005 
00006     @section LICENSE
00007 
00008     Software License Agreement (BSD License)
00009 
00010     Copyright (c) 2016, Jonne Valola
00011     All rights reserved.
00012 
00013     Redistribution and use in source and binary forms, with or without
00014     modification, are permitted provided that the following conditions are met:
00015     1. Redistributions of source code must retain the above copyright
00016     notice, this list of conditions and the following disclaimer.
00017     2. Redistributions in binary form must reproduce the above copyright
00018     notice, this list of conditions and the following disclaimer in the
00019     documentation and/or other materials provided with the distribution.
00020     3. Neither the name of the copyright holders nor the
00021     names of its contributors may be used to endorse or promote products
00022     derived from this software without specific prior written permission.
00023 
00024     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
00025     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00028     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00033     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 */
00035 /**************************************************************************/
00036 
00037 #include "mbed.h"
00038 #include "HWSound.h"
00039 //#include "MCP4018.h"
00040 #include "SoftwareI2C.h"
00041 #include "Pokitto_settings.h "
00042 #include "PokittoDisk.h "
00043 #include "PokittoGlobs.h "
00044 #include "Synth.h "
00045 #include "timer_11u6x.h"
00046 #include "clock_11u6x.h"
00047 #include "HWLCD.h "
00048 //#include "beat_11025.h"
00049 
00050 
00051 Pokitto::Sound __shw;
00052 
00053 #ifdef XPERIMENTAL
00054 DigitalOut e4(EXT4);
00055 e4=0;
00056 #endif
00057 
00058 using namespace Pokitto;
00059 
00060 
00061 
00062 #ifndef POK_SIM
00063 #if POK_ENABLE_SOUND
00064 pwmout_t* obj = &audiopwm;
00065 #endif
00066 #endif
00067 
00068 /** Sound Variables **/
00069 #if (POK_STREAMING_MUSIC > 0)
00070     unsigned char buffers[4][BUFFER_SIZE];
00071     volatile int currentBuffer = 0, oldBuffer = 0;
00072     volatile int bufindex = 0, vol=1;
00073     volatile unsigned char * currentPtr;
00074     volatile unsigned char * endPtr;
00075     int8_t streamvol=3;
00076     uint32_t streamcounter=0;
00077     uint8_t streamstep=0;
00078 #endif
00079 
00080 #if POK_ENABLE_SOUND > 0
00081     pwmout_t Pokitto::audiopwm; // this way (instead of PwmOut class) pwm doesn't start screaming until it is initialized !
00082     //Ticker Pokitto::audio;
00083 
00084 using namespace Pokitto;
00085 
00086 
00087 /** stream output and status */
00088 uint8_t Pokitto::streambyte,Pokitto::streamon;
00089 
00090 uint8_t soundbuf[SBUFSIZE];
00091 uint8_t Pokitto::HWvolume=0;
00092 uint16_t soundbufindex;
00093 uint8_t* soundbufptr;
00094 
00095 bool volpotError=false; //test for broken MCP4018
00096 
00097 uint16_t soundbyte;
00098 
00099 
00100 #if POK_USE_DAC > 0
00101 #if POK_BOARDREV == 1
00102  /** 2-layer board rev 1.3 **/
00103  DigitalOut dac0(P1_6);
00104  DigitalOut dac1(P1_0);
00105  DigitalOut dac2(P1_16);
00106  DigitalOut dac3(P0_19);
00107  DigitalOut dac4(P0_17);
00108  DigitalOut dac5(P1_12);
00109  DigitalOut dac6(P1_15);
00110  DigitalOut dac7(P1_8);
00111 #else
00112  /** 4-layer board rev 2.1 **/
00113  DigitalOut dac0(P1_28);
00114  DigitalOut dac1(P1_29);
00115  DigitalOut dac2(P1_30);
00116  DigitalOut dac3(P1_31);
00117  /* has daniel made a mistake ?*/
00118  DigitalOut dac4(P2_20);
00119  DigitalOut dac5(P2_21);
00120  DigitalOut dac6(P2_22);
00121  DigitalOut dac7(P2_23);
00122 
00123  DigitalOut amp(P1_17);
00124 
00125 #endif // POK_BOARDREV
00126 #endif // POK_USE_DAC
00127 
00128 #if POK_BOARDREV == 2
00129 //MCP4018 volpot(P0_5,P0_4);
00130 
00131 /**
00132  * @brief   Handle interrupt from 32-bit timer 0
00133  * @return  Nothing
00134  */
00135 
00136 uint32_t p=0;
00137 uint8_t pixx=0, pixy=0;
00138 
00139 extern "C" void TIMER32_0_IRQHandler (void)
00140 {
00141     if (Chip_TIMER_MatchPending(LPC_TIMER32_0, 1)) {
00142         Chip_TIMER_ClearMatch(LPC_TIMER32_0, 1);
00143         //pokSoundBufferedIRQ();
00144         #if POK_GBSOUND > 0
00145         /** GAMEBUINO SOUND **/
00146         Pokitto::audio_IRQ();
00147         #else
00148         /** NOT GAMEBUINO SOUND **/
00149             #if POK_SOUND_BUFFERED
00150                 pokSoundBufferedIRQ();
00151             #else
00152                 pokSoundIRQ ();
00153             #endif
00154         #endif
00155     }
00156 }
00157 
00158 
00159 void initHWvolumecontrol() {
00160     HWvolume=0;
00161     volpotError=true;
00162     //if (volpot.put(HWvolume)) volpotError=true; //try if MCP4018 answers
00163     setHWvolume(discrete_vol_hw_levels[VOLUME_STARTUP>>5]);
00164 }
00165 
00166 int Pokitto::setHWvolume(uint8_t v) {
00167     HWvolume=v;
00168     if (HWvolume>127) HWvolume=127;
00169     //HWvolume = 0x7F&v;
00170     //if (!volpotError) return volpot.put(HWvolume); //use normal I2C
00171     /* fallback method for broken MCP4018 */
00172     SoftwareI2C swvolpot(P0_4, P0_5); //swapped SDA,SCL
00173     swvolpot.write(0x5e,HWvolume);
00174     return HWvolume;
00175 }
00176 
00177 uint8_t Pokitto::getHWvolume() {
00178     return HWvolume;
00179 }
00180 
00181 void Pokitto::changeHWvolume(int8_t v) {
00182     int temp  = HWvolume + v;
00183     if (temp < 0) temp = 0; //prevent volume "looparound" than can make a massive crack
00184     if (temp > 127) temp = 127;
00185     setHWvolume(temp);
00186 }
00187 
00188  uint8_t Pokitto::ampIsOn() {
00189     return amp;
00190  }
00191 
00192  void Pokitto::ampEnable(uint8_t v) {
00193     if (v>1) v=1; // limit against funny values
00194     amp=v;
00195  }
00196 #endif // POK_BOARDREV == 2
00197 
00198 void Pokitto::dac_write(uint8_t value) {
00199     #if POK_USE_DAC > 0
00200     #if POK_BOARDREV == 1 // was 1
00201     if (value & 1) SET_DAC0 else CLR_DAC0;
00202     value >>= 1;
00203     if (value & 1) SET_DAC1 else CLR_DAC1;
00204     value >>= 1;
00205     if (value & 1) SET_DAC2 else CLR_DAC2;
00206     value >>= 1;
00207     if (value & 1) SET_DAC3 else CLR_DAC3;
00208     value >>= 1;
00209     if (value & 1) SET_DAC4 else CLR_DAC4;
00210     value >>= 1;
00211     if (value & 1) SET_DAC5 else CLR_DAC5;
00212     value >>= 1;
00213     if (value & 1) SET_DAC6 else CLR_DAC6;
00214     value >>= 1;
00215     if (value & 1) SET_DAC7 else CLR_DAC7;
00216     #else
00217 
00218     //val = value<<28; //lower 4 bits go higher - because port mask is used, no AND is needed to clear bits
00219     //val += value<<(15-4); //higher 4 bits go lower. No need to shift by 15 because bits are in the higher nibble
00220     /* daniel has made a mistake with ports */
00221     //val = ((value&0x70)<<(28-4)); //higher 4 bits go higher - because port mask is used, no AND is needed to clear bits
00222     //val += value<<(15); //lower 4 bits go lower. No need to shift by 15 because bits are in the higher nibble
00223     //SET_MASK_DAC;
00224     //LPC_GPIO_PORT->MPIN[1] = val; // write bits to port
00225     //CLR_MASK_DAC;
00226     /* fixed here */
00227     #define MASKED_DAC 0
00228     #if MASKED_DAC
00229     uint32_t val;
00230     val=value;
00231     SET_MASK_DAC_LO;
00232     LPC_GPIO_PORT->MPIN[1] = val<<28; // write lower 4 bits to port
00233     CLR_MASK_DAC_LO;
00234     SET_MASK_DAC_HI;
00235     LPC_GPIO_PORT->MPIN[2] = val<<(20-4); // write bits to port
00236     CLR_MASK_DAC_HI;
00237     #else
00238     if (value & 1) SET_DAC0 else CLR_DAC0;
00239     value >>= 1;
00240     if (value & 1) SET_DAC1 else CLR_DAC1;
00241     value >>= 1;
00242     if (value & 1) SET_DAC2 else CLR_DAC2;
00243     value >>= 1;
00244     if (value & 1) SET_DAC3 else CLR_DAC3;
00245     value >>= 1;
00246     if (value & 1) SET_DAC4 else CLR_DAC4;
00247     value >>= 1;
00248     if (value & 1) SET_DAC5 else CLR_DAC5;
00249     value >>= 1;
00250     if (value & 1) SET_DAC6 else CLR_DAC6;
00251     value >>= 1;
00252     if (value & 1) SET_DAC7 else CLR_DAC7;
00253     #endif //MASKED_DAC
00254     //CLR_MASK_DAC;
00255     #endif // BOARDREV
00256     #endif
00257 }
00258 
00259 /** SOUND INIT **/
00260 void Pokitto::soundInit() {
00261     #if POK_ENABLE_SOUND > 0
00262     uint32_t timerFreq;
00263     #if POK_USE_PWM
00264 
00265     pwmout_init(&audiopwm,POK_AUD_PIN);
00266     pwmout_period_us(&audiopwm,POK_AUD_PWM_US); //was 31us
00267     pwmout_write(&audiopwm,0.1f);
00268     #endif
00269 
00270     //#if POK_GBSOUND > 0
00271     /** GAMEBUINO SOUND **/
00272     //audio.attach_us(&audio_IRQ, 1000000/(POK_AUD_FREQ>>0));
00273     //#else
00274     /** NOT GAMEBUINO SOUND **/
00275     //audio.attach_us(&pokSoundBufferedIRQ, 1000000/(POK_AUD_FREQ>>0));
00276      /* Initialize 32-bit timer 0 clock */
00277     Chip_TIMER_Init(LPC_TIMER32_0);
00278 
00279     /* Timer rate is system clock rate */
00280     timerFreq = Chip_Clock_GetSystemClockRate();
00281 
00282     /* Timer setup for match and interrupt at TICKRATE_HZ */
00283     Chip_TIMER_Reset(LPC_TIMER32_0);
00284 
00285     /* Enable both timers to generate interrupts when time matches */
00286     Chip_TIMER_MatchEnableInt(LPC_TIMER32_0, 1);
00287 
00288     /* Setup 32-bit timer's duration (32-bit match time) */
00289     Chip_TIMER_SetMatch(LPC_TIMER32_0, 1, (timerFreq / POK_AUD_FREQ));
00290 
00291     /* Setup both timers to restart when match occurs */
00292     Chip_TIMER_ResetOnMatchEnable(LPC_TIMER32_0, 1);
00293 
00294     /* Start both timers */
00295     Chip_TIMER_Enable(LPC_TIMER32_0);
00296 
00297     /* Clear both timers of any pending interrupts */
00298     #define TIMER_32_0_IRQn 18
00299     NVIC_ClearPendingIRQ((IRQn_Type)TIMER_32_0_IRQn);
00300 
00301     /* Redirect IRQ vector - Jonne*/
00302     NVIC_SetVector((IRQn_Type)TIMER_32_0_IRQn, (uint32_t)&TIMER32_0_IRQHandler );
00303 
00304     /* Enable both timer interrupts */
00305     NVIC_EnableIRQ((IRQn_Type)TIMER_32_0_IRQn);
00306     //#endif // POK_GAMEBUINO_SUPPORT
00307 
00308     //emptySong();
00309     //emptyOscillators();
00310     //emptyBlocks();
00311     //emptyPatches();
00312     #ifdef TEST_SOUND
00313         testOsc();
00314     #endif // TEST_SOUND
00315     #if POK_BOARDREV == 2
00316         //initHWvolumecontrol();
00317     #endif
00318 
00319     #if POK_ENABLE_SYNTH
00320         emptyOscillators();
00321     #endif
00322 
00323 
00324     #endif // POK_ENABLE_SOUND
00325 
00326 }
00327 
00328 
00329 uint8_t Pokitto::streamPaused() {
00330     return !streamon;
00331 }
00332 
00333 void Pokitto::pauseStream() {
00334     streamon=0;
00335 }
00336 
00337 void Pokitto::playStream() {
00338     streamon=1;
00339 }
00340 
00341 
00342 void pokPauseStream() {
00343     streamon=0;
00344 }
00345 
00346 void pokPlayStream() {
00347     streamon=1;
00348 }
00349 
00350 
00351 
00352 inline void pokSoundBufferedIRQ() {
00353            uint32_t output = soundbuf[soundbufindex+=Pokitto::streamon];
00354            if (soundbufindex==SBUFSIZE) soundbufindex=0;
00355            //if (p==sizeof(beat_11025_raw)) p=0;
00356            //soundbuf[soundbufindex++] = output;
00357            //uint32_t t_on = (uint32_t)(((obj->pwm->MATCHREL0)*output)>>8); //cut out float
00358            //obj->pwm->MATCHREL1 = t_on;
00359            output *= discrete_vol_multipliers[discrete_vol];
00360            output >>= 8;
00361            dac_write(output);
00362 
00363            //setDRAMpoint(pixx, pixy);
00364 }
00365 
00366 inline void pokSoundIRQ () {
00367     #if POK_ENABLE_SOUND > 0
00368     //#define TICKY 0xFFFF //160
00369     //#define INCY 409
00370     uint32_t output=0;uint32_t op;
00371     //streamon=1;
00372     //if (test==TICKY) test=0;
00373     //if (test<(TICKY/2)) { tpin=1; pwmout_write(&audiopwm,(float)0/(float)255);}//dac_write(0);}
00374     //else {tpin=0; pwmout_write(&audiopwm,(float)255/(float)255);}//dac_write(64);}
00375     //test+=INCY;
00376     //return;
00377     #ifndef POK_SIM
00378         #if POK_USE_PWM
00379         pwmout_t* obj = &audiopwm;
00380         #endif
00381     #endif
00382     #if POK_STREAMING_MUSIC > 0
00383         #if POK_STREAMFREQ_HALVE
00384         streamstep = 1-streamstep;
00385         #else
00386         streamstep = 1;
00387         #endif // POK_STREAMFREQ_HALVE
00388         streamstep &= streamon; // streamon is used to toggle SD music streaming on and off
00389         if (streamstep) {
00390             output = (*currentPtr++);
00391             if(streamvol && streamon) {
00392                 output >>= 3-streamvol;
00393                 streambyte = output;
00394             } else {
00395                 streambyte = 0; // duty cycle
00396                 output = 0;
00397             }
00398             if (currentPtr >= endPtr)
00399             {
00400             currentBuffer++;
00401             if (currentBuffer==4) currentBuffer=0;
00402             currentPtr = buffers[currentBuffer];
00403             endPtr = currentPtr + BUFFER_SIZE;
00404             }
00405         }
00406     #endif // POK_STREAMING_MUSIC
00407 
00408     /** DO ADDITIONAL SOUND PROCESSING (NOT STREAM) OF SOUND HERE **/
00409 
00410     #if POK_ENABLE_SYNTH
00411         /** if song is being played from sd **/
00412         if (playing) {
00413                 notetick++;
00414                 updatePlayback();
00415         }
00416         /** oscillators update **/
00417         osc1.count += osc1.cinc + (osc1.pitchbend >> 4); // counts to 65535 and overflows to zero WAS 8 !
00418         osc2.count += osc2.cinc + (osc2.pitchbend >> 4); // counts to 65535 and overflows to zero
00419         osc3.count += osc3.cinc + (osc3.pitchbend >> 4); // counts to 65535 and overflows to zero
00420         Marr[tick](); // call mixing function
00421         --tick;
00422 
00423         /** mixing oscillator output **/
00424 
00425         op = (uint32_t) ((osc1.output)*(osc1.vol>>8))>>9;// >> 2 osc1.vol Marr;
00426         op += (uint32_t) ((osc2.output)*(osc2.vol>>8))>>9;// >> 2 osc1.vol Marr;
00427         op += (uint32_t) ((osc3.output)*(osc3.vol>>8))>>9;// >> 2 osc1.vol Marr;
00428         op *= discrete_vol_multipliers[discrete_vol];
00429         op >>= 8;
00430         output = op & 0xFF;
00431 
00432     #endif // POK_ENABLE_SYNTH
00433 
00434     #ifndef POK_SIM
00435     /** HARDWARE **/
00436         #if POK_ENABLE_SOUND > 0
00437             #if POK_STREAMING_MUSIC > 0
00438                 /** sound is enabled, streaming is enabled */
00439                 #if POK_STREAM_TO_DAC > 0
00440                     /** stream goes to DAC */
00441                     #if POK_USE_DAC > 0
00442                     uint32_t sbyte = streambyte;
00443                     sbyte *= discrete_vol_multipliers[discrete_vol];
00444                     sbyte >>= 8;
00445                     dac_write((uint8_t)sbyte); // duty cycle
00446                     #endif // POK_USE_DAC
00447                 #else
00448                     /** stream goes to PWM */
00449                     if (streamstep) {
00450                             //pwmout_write(&audiopwm,(float)streambyte/(float)255);
00451                             #if POK_USE_PWM
00452                             uint32_t sbyte = streambyte;
00453                             sbyte *= discrete_vol_multipliers[discrete_vol];
00454                             sbyte >>= 8;
00455                             uint32_t t_on = (uint32_t)((((obj->pwm->MATCHREL0)*sbyte)>>8)); //cut out float
00456                             obj->pwm->MATCHREL1 = t_on;
00457                             #endif
00458                             //dac_write((uint8_t)streambyte); // duty cycle
00459                     }
00460                 #endif // POK_STREAM_TO_DAC
00461             #endif // POK_STREAMING_MUSIC
00462             #if POK_STREAM_TO_DAC > 0
00463                 /** synth goes to PWM */
00464                 //pwmout_write(&audiopwm,(float)output/(float)255);
00465                 #if POK_USE_PWM
00466                     op = output;
00467                     op *= discrete_vol_multipliers[discrete_vol];
00468                     op >>= 8;
00469                     uint32_t t_on = (uint32_t)((((obj->pwm->MATCHREL0)*op)>>8)); //cut out float
00470                     obj->pwm->MATCHREL1 = t_on;
00471                 #endif
00472             #else // POK_STREAMING_MUSIC
00473                 op = output;
00474                 op *= discrete_vol_multipliers[discrete_vol];
00475                 op >>= 8;
00476                 dac_write((uint8_t)op); // SYNTH to DAC
00477             #endif
00478             soundbyte = (output+streambyte)>>1;
00479             soundbuf[soundbufindex++]=soundbyte;
00480             if (soundbufindex==256) soundbufindex=0;
00481         #endif //POK_ENABLE_SOUND
00482     #endif // HARDWARE
00483 #endif //POK_ENABLE_SOUND
00484 }
00485 
00486 
00487 void Pokitto::updateSDAudioStream() {
00488     if (streamPaused()) return;
00489 
00490     #if POK_STREAMING_MUSIC > 0
00491     if (oldBuffer != currentBuffer) {
00492         if (currentBuffer==0) fileReadBytes(&buffers[3][0],BUFFER_SIZE);
00493         else if (currentBuffer==1) fileReadBytes(&buffers[0][0],BUFFER_SIZE);
00494         else if (currentBuffer==2) fileReadBytes(&buffers[1][0],BUFFER_SIZE);
00495         else fileReadBytes(&buffers[2][0],BUFFER_SIZE);
00496         oldBuffer = currentBuffer;
00497         streamcounter += BUFFER_SIZE;
00498     } else return;
00499 
00500     #ifndef POK_SIM
00501     if ( streamcounter > fs.fsize - (BUFFER_SIZE*6)) {
00502     #else
00503     if ( streamcounter > getFileLength() - (BUFFER_SIZE*6)) {
00504     #endif
00505         streamcounter=0;
00506         #if POK_STREAM_LOOP
00507         fileRewind();
00508         #else
00509         pokPauseStream();
00510         #endif
00511     }
00512     #endif
00513 }
00514 
00515 
00516 #endif // POK_ENABLE_SOUND
00517 
00518 
00519