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

Dependents:   Sensitive

Fork of PokittoLib by Jonne Valola

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 
00046 
00047 
00048 using namespace Pokitto;
00049 
00050 /** Sound Variables **/
00051 #if (POK_STREAMING_MUSIC > 0)
00052     unsigned char buffers[4][BUFFER_SIZE];
00053     volatile int currentBuffer = 0, oldBuffer = 0;
00054     volatile int bufindex = 0, vol=1;
00055     volatile unsigned char * currentPtr;
00056     volatile unsigned char * endPtr;
00057     int8_t streamvol=3;
00058     uint32_t streamcounter=0;
00059     uint8_t streamstep=0;
00060 #endif
00061 
00062 #if POK_ENABLE_SOUND > 0
00063     pwmout_t Pokitto::audiopwm; // this way (instead of PwmOut class) pwm doesn't start screaming until it is initialized !
00064     Ticker Pokitto::audio;
00065 
00066 using namespace Pokitto;
00067 
00068 /** stream output and status */
00069 uint8_t Pokitto::streambyte,Pokitto::streamon;
00070 
00071 uint8_t soundbuf[256], soundbufindex=0, Pokitto::HWvolume=0;
00072 bool volpotError=false; //test for broken MCP4018
00073 
00074 uint16_t soundbyte;
00075 
00076 
00077 #if POK_USE_DAC > 0
00078 #if POK_BOARDREV == 1
00079  /** 2-layer board rev 1.3 **/
00080  DigitalOut dac0(P1_6);
00081  DigitalOut dac1(P1_0);
00082  DigitalOut dac2(P1_16);
00083  DigitalOut dac3(P0_19);
00084  DigitalOut dac4(P0_17);
00085  DigitalOut dac5(P1_12);
00086  DigitalOut dac6(P1_15);
00087  DigitalOut dac7(P1_8);
00088 #else
00089  /** 4-layer board rev 2.1 **/
00090  DigitalOut dac0(P1_28);
00091  DigitalOut dac1(P1_29);
00092  DigitalOut dac2(P1_30);
00093  DigitalOut dac3(P1_31);
00094  /* has daniel made a mistake ?*/
00095  DigitalOut dac4(P2_20);
00096  DigitalOut dac5(P2_21);
00097  DigitalOut dac6(P2_22);
00098  DigitalOut dac7(P2_23);
00099 
00100  DigitalOut amp(P1_17);
00101 
00102 #endif // POK_BOARDREV
00103 #endif // POK_USE_DAC
00104 
00105 #if POK_BOARDREV == 2
00106 //MCP4018 volpot(P0_5,P0_4);
00107 
00108 void initHWvolumecontrol() {
00109     HWvolume=0;
00110     volpotError=true;
00111     //if (volpot.put(HWvolume)) volpotError=true; //try if MCP4018 answers
00112     setHWvolume(VOLUME_STARTUP);
00113 }
00114 
00115 int Pokitto::setHWvolume(uint8_t v) {
00116     HWvolume = 0x7F&v;
00117     //if (!volpotError) return volpot.put(HWvolume); //use normal I2C
00118     /* fallback method for broken MCP4018 */
00119     SoftwareI2C swvolpot(P0_4, P0_5); //swapped SDA,SCL
00120     swvolpot.write(0x5e,HWvolume);
00121     return HWvolume;
00122 }
00123 
00124 uint8_t Pokitto::getHWvolume() {
00125     return HWvolume;
00126 }
00127 
00128 void Pokitto::changeHWvolume(int8_t v) {
00129     int temp  = HWvolume + v;
00130     if (temp < 0) temp = 0; //prevent volume "looparound" than can make a massive crack
00131     if (temp > 127) temp = 127;
00132     setHWvolume(temp);
00133 }
00134 
00135  uint8_t Pokitto::ampIsOn() {
00136     return amp;
00137  }
00138 
00139  void Pokitto::ampEnable(uint8_t v) {
00140     if (v>1) v=1; // limit against funny values
00141     amp=v;
00142  }
00143 #endif // POK_BOARDREV == 2
00144 
00145 void Pokitto::dac_write(uint8_t value) {
00146     #if POK_USE_DAC > 0
00147     #if POK_BOARDREV == 1 // was 1
00148     if (value & 1) SET_DAC0 else CLR_DAC0;
00149     value >>= 1;
00150     if (value & 1) SET_DAC1 else CLR_DAC1;
00151     value >>= 1;
00152     if (value & 1) SET_DAC2 else CLR_DAC2;
00153     value >>= 1;
00154     if (value & 1) SET_DAC3 else CLR_DAC3;
00155     value >>= 1;
00156     if (value & 1) SET_DAC4 else CLR_DAC4;
00157     value >>= 1;
00158     if (value & 1) SET_DAC5 else CLR_DAC5;
00159     value >>= 1;
00160     if (value & 1) SET_DAC6 else CLR_DAC6;
00161     value >>= 1;
00162     if (value & 1) SET_DAC7 else CLR_DAC7;
00163     #else
00164     //uint32_t val;
00165     //val = value<<28; //lower 4 bits go higher - because port mask is used, no AND is needed to clear bits
00166     //val += value<<(15-4); //higher 4 bits go lower. No need to shift by 15 because bits are in the higher nibble
00167     /* daniel has made a mistake with ports */
00168     //val = ((value&0x70)<<(28-4)); //higher 4 bits go higher - because port mask is used, no AND is needed to clear bits
00169     //val += value<<(15); //lower 4 bits go lower. No need to shift by 15 because bits are in the higher nibble
00170     //SET_MASK_DAC;
00171     //LPC_GPIO_PORT->MPIN[1] = val; // write bits to port
00172     //CLR_MASK_DAC;
00173     /* fixed here */
00174     /*val=value;
00175     SET_MASK_DAC_LO;
00176     LPC_GPIO_PORT->MPIN[1] = val<<28; // write lower 4 bits to port
00177     CLR_MASK_DAC_LO;
00178     SET_MASK_DAC_HI;
00179     LPC_GPIO_PORT->MPIN[2] = val<<(20-4); // write bits to port
00180     CLR_MASK_DAC_HI; */
00181     if (value & 1) SET_DAC0 else CLR_DAC0;
00182     value >>= 1;
00183     if (value & 1) SET_DAC1 else CLR_DAC1;
00184     value >>= 1;
00185     if (value & 1) SET_DAC2 else CLR_DAC2;
00186     value >>= 1;
00187     if (value & 1) SET_DAC3 else CLR_DAC3;
00188     value >>= 1;
00189     if (value & 1) SET_DAC4 else CLR_DAC4;
00190     value >>= 1;
00191     if (value & 1) SET_DAC5 else CLR_DAC5;
00192     value >>= 1;
00193     if (value & 1) SET_DAC6 else CLR_DAC6;
00194     value >>= 1;
00195     if (value & 1) SET_DAC7 else CLR_DAC7;
00196     //CLR_MASK_DAC;
00197     #endif // BOARDREV
00198     #endif
00199 }
00200 
00201 /** SOUND INIT **/
00202 void Pokitto::soundInit() {
00203 
00204     pwmout_init(&audiopwm,POK_AUD_PIN);
00205     pwmout_period_us(&audiopwm,POK_AUD_PWM_US); //was 31us
00206     pwmout_write(&audiopwm,0.1f);
00207 
00208     #if POK_GBSOUND > 0
00209     /** GAMEBUINO SOUND **/
00210     audio.attach_us(&audio_IRQ, 1000000/(POK_AUD_FREQ>>0));
00211     #else
00212     /** NOT GAMEBUINO SOUND **/
00213     audio.attach_us(&pokSoundIRQ , 1000000/(POK_AUD_FREQ>>0));
00214     #endif // POK_GAMEBUINO_SUPPORT
00215 
00216     //emptySong();
00217     //emptyOscillators();
00218     //emptyBlocks();
00219     //emptyPatches();
00220     #ifdef TEST_SOUND
00221         testOsc();
00222     #endif // TEST_SOUND
00223     #if POK_BOARDREV == 2
00224         initHWvolumecontrol();
00225     #endif
00226 
00227 }
00228 
00229 
00230 uint8_t Pokitto::streamPaused() {
00231     return !streamon;
00232 }
00233 
00234 void Pokitto::pauseStream() {
00235     streamon=0;
00236 }
00237 
00238 void Pokitto::playStream() {
00239     streamon=1;
00240 }
00241 
00242 
00243 void pokPauseStream() {
00244     streamon=0;
00245 }
00246 
00247 void pokPlayStream() {
00248     streamon=1;
00249 }
00250 
00251 void pokSoundIRQ () {
00252     uint8_t output=0;
00253     #ifndef POK_SIM
00254     //pwmout_t* obj = &audiopwm;
00255     #endif
00256     #if POK_STREAMING_MUSIC > 0
00257         #if POK_STREAMFREQ_HALVE
00258         streamstep = 1-streamstep;
00259         #else
00260         streamstep = 1;
00261         #endif // POK_STREAMFREQ_HALVE
00262         streamstep &= streamon; // streamon is used to toggle SD music streaming on and off
00263         if (streamstep) {
00264             output = (*currentPtr++);
00265             if(streamvol && streamon) {
00266                 output >>= 3-streamvol;
00267                 streambyte = output;
00268             } else {
00269                 streambyte = 0; // duty cycle
00270                 output = 0;
00271             }
00272             if (currentPtr >= endPtr)
00273             {
00274             currentBuffer++;
00275             if (currentBuffer==4) currentBuffer=0;
00276             currentPtr = buffers[currentBuffer];
00277             endPtr = currentPtr + BUFFER_SIZE;
00278             }
00279         }
00280     #endif // POK_STREAMING_MUSIC
00281 
00282     /** DO ADDITIONAL SOUND PROCESSING (NOT STREAM) OF SOUND HERE **/
00283 
00284     #if POK_ENABLE_SYNTH
00285         /** if song is being played from sd **/
00286         if (playing) {
00287                 notetick++;
00288                 updatePlaybackSD(playerpos&7);
00289         }
00290         /** oscillators update **/
00291         osc1.count += osc1.cinc + (osc1.pitchbend >> 4); // counts to 65535 and overflows to zero WAS 8 !
00292         osc2.count += osc2.cinc + (osc2.pitchbend >> 4); // counts to 65535 and overflows to zero
00293         osc3.count += osc3.cinc + (osc3.pitchbend >> 4); // counts to 65535 and overflows to zero
00294         Marr[tick](); // call mixing function
00295         --tick;
00296 
00297         /** mixing oscillator output **/
00298 
00299         uint16_t op = (uint16_t) ((osc1.output)*(osc1.vol>>8))>>9;// >> 2 osc1.vol Marr;
00300         op += (uint16_t) ((osc2.output)*(osc2.vol>>8))>>9;// >> 2 osc1.vol Marr;
00301         op += (uint16_t) ((osc3.output)*(osc3.vol>>8))>>9;// >> 2 osc1.vol Marr;
00302         output = (uint8_t) op;
00303 
00304     #endif // POK_ENABLE_SYNTH
00305 
00306     #ifndef POK_SIM
00307     /** HARDWARE **/
00308         #if POK_ENABLE_SOUND > 0
00309             #if POK_STREAMING_MUSIC > 0
00310                 /** sound is enabled, streaming is enabled */
00311                 #if POK_STREAM_TO_DAC > 0
00312                     /** stream goes to DAC */
00313                     #if POK_USE_DAC > 0
00314                     if (streamstep) dac_write((uint8_t)streambyte); // duty cycle
00315                     #endif // POK_USE_DAC
00316                 #else
00317                     /** stream goes to PWM */
00318                     if (streamstep) {
00319                             pwmout_write(&audiopwm,(float)streambyte/(float)255);
00320                             //uint32_t t_on = (uint32_t)(((obj->pwm->MATCHREL0)*streambyte)>>8); //cut out float
00321                             //obj->pwm->MATCHREL1 = t_on;
00322                             //dac_write((uint8_t)streambyte); // duty cycle
00323                     }
00324                 #endif // POK_STREAM_TO_DAC
00325             #endif // POK_STREAMING_MUSIC
00326             #if POK_STREAM_TO_DAC > 0
00327             /** synth goes to PWM */
00328             pwmout_write(&audiopwm,(float)output/(float)255);
00329             //uint32_t t_on = (uint32_t)(((obj->pwm->MATCHREL0)*output)>>8); //cut out float
00330             //obj->pwm->MATCHREL1 = t_on;
00331             #else
00332             dac_write((uint8_t)output);
00333             #endif // decide where synth is output
00334             soundbyte = (output+streambyte)>>1;
00335             soundbuf[soundbufindex++]=soundbyte;
00336         #endif //POK_ENABLE_SOUND
00337     #endif // HARDWARE
00338 }
00339 
00340 
00341 void Pokitto::updateSDAudioStream() {
00342     if (streamPaused()) return;
00343 
00344     #if POK_STREAMING_MUSIC > 0
00345     if (oldBuffer != currentBuffer) {
00346         if (currentBuffer==0) fileReadBytes(&buffers[3][0],BUFFER_SIZE);
00347         else if (currentBuffer==1) fileReadBytes(&buffers[0][0],BUFFER_SIZE);
00348         else if (currentBuffer==2) fileReadBytes(&buffers[1][0],BUFFER_SIZE);
00349         else fileReadBytes(&buffers[2][0],BUFFER_SIZE);
00350         oldBuffer = currentBuffer;
00351         streamcounter += BUFFER_SIZE;
00352     } else return;
00353 
00354     #ifndef POK_SIM
00355     if ( streamcounter > fs.fsize - (BUFFER_SIZE*6)) {
00356     #else
00357     if ( streamcounter > getFileLength() - (BUFFER_SIZE*6)) {
00358     #endif
00359         streamcounter=0;
00360         #if POK_STREAM_LOOP
00361         fileRewind();
00362         #else
00363         pokPauseStream();
00364         #endif
00365     }
00366     #endif
00367 }
00368 
00369 
00370 #endif // POK_ENABLE_SOUND
00371 
00372