Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members | Related Pages

sid_epoc32.i

Go to the documentation of this file.
00001 
00007 #ifdef __ER6__
00008 #include <e32hal.h>
00009 #include "e32frodo.h"
00010 #else
00011 #include "alaw.h"
00012 #endif
00013 
00014 
00015 // #define PCM_DUMP
00016 
00028 #ifdef __ER6__
00029 
00033 const TInt KDefaultBufSize = 256;
00034 const TInt KMaxSoundBufSize = 2048;
00035 #else
00036 const TInt KDefaultBufSize = 512;
00037 #endif
00038 
00039 void DigitalRenderer::init_sound()
00043         {
00044 #ifdef __ER6__
00045 
00046         ELOG1(_L8("DigitalRenderer::init_sound()\n"));
00047         ready = false; // assume the worst
00048         divisor = to_output = buffer_pos = 0;
00049 #ifdef _DEBUG
00050         iLastVolumeSet = 0;
00051 #endif
00052         the_c64->iSoundHaveBeenPaused = ETrue; // Causes reset_sync() to be called
00053 
00054         TTimeIntervalMicroSeconds32 period;
00055         UserHal::TickPeriod(period);
00056         iTickPeriod_ys = period.Int();
00057 
00058         sound_buffer = new int16[KMaxSoundBufSize];
00059         sound_buffer_desc.Set((TUint8 *)sound_buffer, KDefaultBufSize*2);
00060 
00061         /*
00062          * open audio stream
00063          */
00064         iSettings.iCaps = 0;                    
00065         iSettings.iMaxVolume = 0;               
00066 
00067         iStream = CMdaAudioOutputStream::NewL(*this);
00068         iStream->Open(&iSettings);
00069 
00070         the_c64->iIsAudioPending = ETrue;
00071 
00072 #else // __ER6__
00073 
00074         divisor = to_output = buffer_pos = 0;
00075         ready = false; // asume the worst
00076 
00077         /*
00078          * open sound device
00079          */
00080         TInt ret = iDevSound.Open();
00081         if (ret != KErrNone)
00082                 {
00083                 ELOG2(_L8("AUDIO: could not open sound device [ret=%d]\n"), ret);
00084                 return;
00085                 }
00086 
00087         /*
00088          * get sound device capabilites
00089          */ 
00090         TSoundCaps sndCaps;
00091         iDevSound.Caps(sndCaps);
00092         ELOG1(_L8("AUDIO: RDevSound - caps:\n"));
00093         ELOG2(_L8("  iService      = 0x%08x\n"), sndCaps().iService);
00094         ELOG2(_L8("  iVolume       = 0x%08x\n"), sndCaps().iVolume);
00095         ELOG2(_L8("  iMaxVolume    = 0x%08x\n"), sndCaps().iMaxVolume);
00096         ELOG2(_L8("  iMaxFrequency = 0x%08x\n"), sndCaps().iMaxFrequency);
00097 
00101         TSoundConfig sndConfig;
00102         iDevSound.Config(sndConfig); // read the default config
00103 
00104         sndConfig().iVolume = EVolumeByValue; // 4
00105 //      sndConfig().iVolumeValue = sndCaps().iMaxVolume; @todo
00106         sndConfig().iVolumeValue = 1;
00107         sndConfig().iAlawBufferSize = KDefaultBufSize * 2; // double buffering
00108         
00109         ret = iDevSound.SetConfig(sndConfig);
00110         if(ret != KErrNone)
00111                 {
00112                 ELOG2(_L8("AUDIO: WARNING! Could not set config due to [%d]\n"), ret);
00113                 iDevSound.Close();
00114                 return;
00115                 }
00116 
00117         ELOG2(_L8("AUDIO: iVolume         %d \n"), sndConfig().iVolume );
00118         ELOG2(_L8("       iAlawBufferSize %d \n"), sndConfig().iAlawBufferSize );
00119 
00123         ret = iDevSound.PreparePlayAlawBuffer(); // This *must* be done before reading the Buffer size!!!
00124         if(ret != KErrNone)
00125                 {
00126                 ELOG2(_L8("AUDIO: WARNING! could not prepare alaw buffer due to [%d]\n"), ret);
00127                 return;
00128                 }
00129 
00130         sound_buffer = new int16[KDefaultBufSize];
00131         iAlawBuffer = HBufC8::New(KDefaultBufSize);
00132         if(!sound_buffer || !iAlawBuffer)
00133                 {
00134                 ELOG1(_L8("AUDIO: no memory left for audio buffers :(\n"));
00135                 iDevSound.Close();
00136                 return;
00137                 }
00138 
00139         ELOG1(_L8("AUDIO: the SID chip is ready to Rock'n'Roll...\n"));
00140         ready = true;
00141 
00142 #endif // __ER6__
00143         }
00144 
00145 
00146 void DigitalRenderer::reset_sync()
00150         {
00151         iCountSampleBlocksCopied = 0;
00152         iStartPlayTickCount = User::TickCount(); 
00153         iAudioStarvation = EFalse;
00154 
00155 #ifdef _DEBUG
00156         // For debugging
00157         CE32FrodoAppView* appView = the_c64->iFrodoPtr->iDocPtr->iAppUiPtr->iAppView;
00158         appView->iSidDebugData = this;
00159         iTickPeriod_ys2 = iTickPeriod_ys;
00160         iLeadInBlocks = 0;
00161         iCountSamplesCopied = 0;
00162         iPrevCountSamplesCopied = 0;
00163         iCountDuplicatedBlocks = 0;
00164         iCountSkippedBlocks = 0;
00165         iCountNormalBlocks = 0;
00166         iCountExtraBlocks = 0;
00167         iPlayCompleteCounter = 0;
00168         iBufferLengthTooBigCounter = 0;
00169         iPrevTickCount = 0;
00170 #endif
00171         }
00172 
00173 
00174 DigitalRenderer::~DigitalRenderer()
00178         {
00179 #ifdef __ER6__
00180 
00181         if (iStream)
00182                 {
00183                 if (ready)
00184                         iStream->Stop();
00185                 delete iStream;
00186                 }
00187         delete sound_buffer;
00188 
00189 #ifdef _DEBUG
00190         // For debugging
00191         CE32FrodoAppView* appView = the_c64->iFrodoPtr->iDocPtr->iAppUiPtr->iAppView;
00192         appView->iSidDebugData = NULL;
00193 #endif
00194 
00195 #else // !__ER6__
00196 
00197         delete iAlawBuffer;
00198         delete sound_buffer;
00199         iDevSound.Close();
00200 
00201 #endif
00202         }
00203 
00204 
00205 void DigitalRenderer::Pause(void)
00209         {
00210         }
00211 
00212 
00213 void DigitalRenderer::Resume(void)
00217         {
00218         }
00219 
00220 
00221 void DigitalRenderer::EmulateLine(void)
00225         {
00226         if (!ready)
00227                 return;
00228 
00229         sample_buf[sample_in_ptr] = volume;
00230         sample_in_ptr = (sample_in_ptr + 1) % SAMPLE_BUF_SIZE;
00231 
00232         /*
00233          * Now see how many samples have to be added for this line
00234          */
00235         divisor += SAMPLE_FREQ;
00236         while (divisor >= 0)
00237                 divisor -= TOTAL_RASTERS*SCREEN_FREQ, to_output++;
00238 
00239         /*
00240          * Calculate the sound data only when we have enough to fill
00241          * the buffer entirely.
00242          */
00243         if ((buffer_pos + to_output) >= KDefaultBufSize)
00244                 {
00245                 int datalen = KDefaultBufSize - buffer_pos;
00246                 to_output -= datalen;
00247                 calc_buffer(sound_buffer + buffer_pos, datalen*2);
00248 
00249 #ifdef PCM_DUMP
00250 
00251                 _LIT(KPcmDumpFile, "c:\\e32frodo_pcm.dat");
00252                 const TInt KFileOpenWritable = EFileWrite | EFileShareAny | EFileStream;
00253                 
00254                 RFs fs;
00255                 TInt ret = fs.Connect();
00256                 if( (ret == KErrNone) || (ret == KErrAlreadyExists) )
00257                         {
00258                         RFile file;
00259                         ret = file.Open(fs, KPcmDumpFile, KFileOpenWritable);
00260                         if(ret == KErrNotFound)
00261                                 ret = file.Replace(fs, KPcmDumpFile, KFileOpenWritable);
00262                         if(ret == KErrNone)
00263                                 {
00264                                 TInt pos;
00265                                 ret = file.Seek(ESeekEnd, pos);
00266                                 if (ret==KErrNone)
00267                                         {
00268                                         TPtrC8 ptr((unsigned char*)sound_buffer, KDefaultBufSize*2); // 2x8 = 16
00269                                         file.Write(ptr);
00270                                         }
00271                                 else
00272                                         {
00273                                         ELOG2(_L8("PCMDUMP: could not seek due to %d\n"), ret);
00274                                         }
00275                                 
00276                                 file.Close();
00277                                 }
00278                         else
00279                                 {
00280                                 ELOG2(_L8("PCMDUMP: could not open file due to %d\n"), ret);
00281                                 }
00282                         
00283                         fs.Close();
00284                         }
00285 
00286 #else // PCM_DUMP
00287 
00288 #ifdef __ER6__
00289 
00290                 /*
00291                  * Reset audio sync if there has been a pause
00292                  */
00293                 if (the_c64->iSoundHaveBeenPaused)
00294                         {
00295                         the_c64->iSoundHaveBeenPaused = EFalse;
00296                         reset_sync();
00297                         }
00298 
00302                 TUint elapsedTics = User::TickCount() - iStartPlayTickCount + 1; // Add one to get a fast start
00303                 TUint elapsedBlocks_ys = elapsedTics * iTickPeriod_ys;
00304                 TUint countElapsedBlocks  = (elapsedBlocks_ys * (SAMPLE_FREQ/1000)) / (1000 * KDefaultBufSize);
00305                 iLeadInBlocks = iCountSampleBlocksCopied - countElapsedBlocks;
00306 
00307                 /*
00308                  * Synchronize audio: If we are not in sync, either duplicate or skip current sample block.
00309                  * If we are lagging too much (emu speed is < 50%), even duplicating every block is not enough 
00310                  * and there will be breaks in audio.
00311                  *
00312                  * @todo there might be some variable overflow problems if audio is running a long time without resync()...
00313                  */
00314                 if ((iLeadInBlocks < -ThePrefs.LatencyMax) || iAudioStarvation)
00315                         {
00316                         // Duplicate current block.
00317                         Mem::Copy((TUint8 *)sound_buffer + KDefaultBufSize*2, sound_buffer, KDefaultBufSize*2);
00318                         sound_buffer_desc.Set((TUint8 *)sound_buffer, 2 * KDefaultBufSize*2);
00319                         if (iLeadInBlocks < -ThePrefs.LatencyMax)
00320                                 {
00321                                 iCountSampleBlocksCopied++;
00322                                 iCountSamplesCopied += KDefaultBufSize; // Only for debug !! TODO: Handle overflow!
00323                                 iCountDuplicatedBlocks++; // Only for debug
00324                                 }
00325                         else
00326                                 {
00327                                 // Adds extra blocks to fix starvation. Do not count these blocks in any other counters.
00328                                 iCountExtraBlocks++;
00329                                 iAudioStarvation = EFalse;
00330                                 }
00331                         }
00332                 else
00333                         {
00334                         sound_buffer_desc.Set((TUint8 *)sound_buffer, KDefaultBufSize*2);
00335                         }
00336                 if (iLeadInBlocks <= ThePrefs.LatencyMax) 
00337                         {
00338                         // No need to skip. Play current block.
00339                         iStream->WriteL(sound_buffer_desc);
00340                         iCountSampleBlocksCopied++;
00341                         iCountNormalBlocks++;
00342                         iCountSamplesCopied += KDefaultBufSize; // Only for debug !! TODO: Handle overflow!
00343                         // Only one block at a time
00344                         the_c64->iIsAudioPending = ETrue;
00345                         }
00346                 else
00347                         {
00348                         // Skipped
00349                         iCountSkippedBlocks++; // Only for debug
00350                         }
00351 
00352 #else // __ER6__
00353 
00354                 //
00355                 // convert from linear PCM to aLaw first
00356                 //
00357                 TPtr8 alawPtr = iAlawBuffer->Des();
00358                 alawPtr.SetLength(KDefaultBufSize);
00359                 Alaw::conv_s16bit_alaw((unsigned short*)sound_buffer, &alawPtr[0], KDefaultBufSize);
00360                 
00361                 //
00362                 // and then play the Alaw buffer
00363                 //
00364                 TRequestStatus stat;
00365                 iDevSound.PlayAlawData(stat, alawPtr);
00366                 User::WaitForRequest(stat);
00367                 TInt ret = stat.Int();
00368                 if(ret != KErrNone)
00369                         {
00370                         ELOG2(_L8("AUDIO: Warning! could not play due to %d\n"), ret);
00371                         }
00372 #endif // __ER6__
00373 
00374 #endif // PCM_DUMP
00375 
00376 //
00377 // this is how they do it on Linux:
00378 //
00379 //              write(devfd, sound_buffer, sndbufsize*2);
00380 
00381                 buffer_pos = 0;
00382                 }
00383 
00384         }
00385 
00386 #ifdef __ER6__
00387 
00388 
00389 void DigitalRenderer::MaoscOpenComplete(TInt aError)
00393         {
00394         ELOG1(_L8("DigitalRenderer::MaoscOpenComplete()\n"));
00395         iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate8000Hz, 
00396                                                                  TMdaAudioDataSettings::EChannelsMono);
00397         ready = true;
00398         the_c64->iIsAudioPending = EFalse;
00399         the_c64->iFrodoPtr->StartC64();
00400 
00401         SetVolumeL(ThePrefs.iVolume);
00402         iStream->SetPriority(EPriorityNormal, EMdaPriorityPreferenceNone);
00403         ELOG1(_L8("DigitalRenderer::MaoscOpenComplete() end\n"));
00404         }
00405 
00406 
00407 void DigitalRenderer::MaoscBufferCopied(TInt aError, const TDesC8& aBuffer)
00411         {
00412         the_c64->iIsAudioPending = EFalse;
00413         the_c64->iFrodoPtr->StartC64();
00414         }
00415 
00416 
00417 void DigitalRenderer::MaoscPlayComplete(TInt aError)
00421         {
00422         iPlayCompleteCounter++; // Only for debug
00423         iAudioStarvation = ETrue;
00424         }
00425 
00426 
00427 void DigitalRenderer::SetVolumeL(TInt aVolume)
00431         {
00432         if (!ready)
00433                         return;
00434         TInt newVolume(aVolume);
00435         if(newVolume > 100)
00436                 newVolume = iStream->MaxVolume();
00437         else if(newVolume < 0)
00438                 newVolume = 0;
00439 #ifdef _DEBUG
00440         iLastVolumeSet = newVolume;
00441 #endif
00442         newVolume = (newVolume*iStream->MaxVolume())/100;
00443         iStream->SetVolume(newVolume);
00444         }
00445 
00446 #endif
00447 
00448 
00449 //
00450 // this code is moved here from FixPoint.i to avoid global data
00451 //
00452 
00454 //FixPoint SinTable[(1<<ldSINTAB)];
00455 
00456 
00457 #define FIXPOINT_SIN_COS_GENERIC \
00458   if (angle >= 3*(1<<ldSINTAB)) {return(-SinTable[(1<<(ldSINTAB+2)) - angle]);}\
00459   if (angle >= 2*(1<<ldSINTAB)) {return(-SinTable[angle - 2*(1<<ldSINTAB)]);}\
00460   if (angle >= (1<<ldSINTAB)) {return(SinTable[2*(1<<ldSINTAB) - angle]);}\
00461   return(SinTable[angle]);
00462 
00463 
00464 // sin and cos: angle is fixpoint number 0 <= angle <= 2 (*PI)
00465 inline FixPoint DigitalRenderer::fixsin(FixPoint x)
00466 {
00467   int angle = x;
00468 
00469   angle = (angle >> (FIXPOINT_PREC - ldSINTAB - 1)) & ((1<<(ldSINTAB+2))-1);
00470   FIXPOINT_SIN_COS_GENERIC
00471 }
00472 
00473 
00474 inline FixPoint DigitalRenderer::fixcos(FixPoint x)
00475 {
00476   int angle = x;
00477 
00478   // cos(x) = sin(x+PI/2)
00479   angle = (angle + (1<<(FIXPOINT_PREC-1)) >> (FIXPOINT_PREC - ldSINTAB - 1)) & ((1<<(ldSINTAB+2))-1);
00480   FIXPOINT_SIN_COS_GENERIC
00481 }
00482 
00483 
00484 inline void DigitalRenderer::InitFixSinTab(void)
00485 {
00486  ELOG2(_L8("InitFixSinTab [SinTable=0x%08x] ..."), SinTable);
00487   int i;
00488   float step;
00489 
00490   for (i=0, step=0; i<(1<<ldSINTAB); i++, step+=0.5/(1<<ldSINTAB))
00491   {
00492     SinTable[i] = FixNo(sin(M_PI * step));
00493   }
00494   ELOG1(_L8("[  OK  ]\n"));
00495 }

Generated on Tue Feb 8 04:08:12 2005 for E32frodo by doxygen 1.3.3