// // Programmer // // Date init 14.12.2004 // // Reviser $Author:: Dkandlun $ // // Revision date $Date:: 14-11-07 12:40 $ // // Filename $Workfile:: d_sound.r $ // // Version $Revision:: 1 $ // // Archive $Archive:: /LMS2006/Sys01/Main_V02/Firmware/Source/d_soun $ // // Platform C // #include "d_sound_adpcm.r" #ifdef SAM7S256 #define SAMPLEMIN 0 // Must be zero (no pwm/interrupt) #define SAMPLEMAX 256 // Must be 256 (8 bit wave format) #define SAMPLECENTER (((SAMPLEMAX - SAMPLEMIN) / 2) + SAMPLEMIN) #define SAMPLEWORD ULONG #define SAMPLEWORDS 8 #define SAMPLEWORDBITS (sizeof(SAMPLEWORD) * 8) #define SAMPLEBITS (SAMPLEWORDS * SAMPLEWORDBITS) #define SAMPLECONSTANT 3 // >> == (SAMPLEMAX / SAMPLEWORDBITS) #define SAMPLETONENO 16 // No of tone samples #define SAMPLEBUFFERS 2 #define INIT_PREV_VAL_ADPCM 0x7F #define INIT_INDEX_ADPCM 20 SAMPLEWORD SampleBuffer[SAMPLEBUFFERS][SAMPLEWORDS]; SAMPLEWORD ToneBuffer[SAMPLETONENO]; const SAMPLEWORD TonePattern[SOUNDVOLUMESTEPS + 1][SAMPLETONENO] = { { 0xF0F0F0F0,0xF0F0F0F0, // Step 0 = silence 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0 }, { 0xF0F0F0F0,0xF0F0F0F0, // Step 1 = 1/512 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F8, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0 }, { 0xF0F0F0F0,0xF0F0F0F0, // Step 2 = 0,+3,+4,+3,0,-3,-4,-3 0xF0F0F0F0,0xF0F8F8F8, 0xF0F0F8F8,0xF8F8F0F0, 0xF8F8F8F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0F0F0F0, 0xF0F0F0F0,0xF0E0E0E0, 0xF0F0E0E0,0xE0E0F0F0, 0xE0E0E0F0,0xF0F0F0F0 }, { 0xF0F0F0F0,0xF0F0F0F0, // Step 3 = 0,+10,+14,+10,0,-10,-14,-10 0xF8F8F8F8,0xF8F8FCFC, 0xF8F8FCFC,0xFCFCFCFC, 0xFCFCF8F8,0xF8F8F8F8, 0xF0F0F0F0,0xF0F0F0F0, 0xE0E0E0E0,0xE0E0C0C0, 0xE0E0C0C0,0xC0C0C0C0, 0xC0C0E0E0,0xE0E0E0E0 }, { 0xF0F0F0F0,0xF0F0F0F0, // Step 4 = 0,+22,+32,+22,0,-22,-32,-22 0xFCFCFCFC,0xFCFCFDFD, 0xFFFFFFFF,0xFFFFFFFF, 0xFDFDFCFC,0xFCFCFCFC, 0xF0F0F0F0,0xF0F0F0F0, 0xC0C0C0C0,0xC0C08080, 0x00000000,0x00000000, 0x8080C0C0,0xC0C0C0C0 } }; __ramdata UBYTE FractionPattern[SAMPLEWORDS] = { 0x00, // 0 -> 00000000 0x10, // 1 -> 00010000 0x22, // 2 -> 00100010 0x4A, // 3 -> 01001010 0x55, // 4 -> 01010101 0x6D, // 5 -> 01101101 0x77, // 6 -> 01110111 0x7F, // 7 -> 01111111 }; typedef struct { SWORD Valprev; // Previous output value SWORD Index; // Index into stepsize table }ADPCM_State; ULONG ToneCycles; // No of tone cycles ULONG ToneCyclesReady; // No of tone cycles for ready ULONG ClockNext; // Serial clock for next buffer UBYTE *pSoundPointer; // Pointer to sample in actual sound buffer UBYTE *pSoundPointerNext; // Pointer to sample in next sound buffer UWORD SoundSamplesLeft; // Number of samples left on actual sound buffer UWORD SoundSamplesLeftNext; // Number of samples left on next sound buffer UBYTE SampleBufferNo; // Sample buffer no in use UBYTE SoundReady; // Sound channel ready (idle) UBYTE SoundDivider; // Volume UWORD MelodyPointer; UBYTE CurrentFileFormat; // Hold current playing file type UBYTE Outdata[2]; // Output buffer used within the ADPCM algorithm ADPCM_State State; // Struct holding ADPCM state #define SOUNDIntEnable {\ *AT91C_SSC_IER = AT91C_SSC_ENDTX;\ } #define SOUNDIntDisable {\ *AT91C_SSC_IDR = AT91C_SSC_ENDTX;\ } #define SOUNDEnable {\ *AT91C_PIOA_PDR = AT91C_PA17_TD; /* Enable TD on PA17 */\ } #define SOUNDDisable {\ *AT91C_PIOA_PER = AT91C_PA17_TD; /* Disable TD on PA17 */\ } ULONG SoundSampleRate(UWORD Rate) { ULONG Result; if (Rate > SAMPLERATE_MAX) { Rate = SAMPLERATE_MAX; } if (Rate < SAMPLERATE_MIN) { Rate = SAMPLERATE_MIN; } Result = ((OSC / (2 * SAMPLEBITS)) / Rate) + 1; return (Result); } __ramfunc void CalculateBitstream(SAMPLEWORD *pSampleBuffer,UBYTE Sample) { ULONG IntegerMask; ULONG FractionMask; UBYTE Integer; UBYTE Fraction; UBYTE Mask; UBYTE Tmp; SWORD STmp; if (SoundDivider) { STmp = Sample; STmp &= 0xFF; STmp -= SAMPLECENTER; STmp >>= (SOUNDVOLUMESTEPS - SoundDivider); STmp += SAMPLECENTER; Sample = (UBYTE)STmp; SOUNDEnable; } else { SOUNDDisable; } Tmp = 0; IntegerMask = 0xFFFF0000; Integer = Sample >> SAMPLECONSTANT; Fraction = Sample - (Integer << SAMPLECONSTANT); IntegerMask = 0xFFFFFFFF << (SAMPLEWORDBITS - Integer); FractionMask = (IntegerMask >> 1) | IntegerMask; Mask = FractionPattern[Fraction]; while (Tmp < SAMPLEWORDS) { if ((Mask & (0x01 << Tmp))) { *pSampleBuffer = FractionMask; } else { *pSampleBuffer = IntegerMask; } pSampleBuffer++; Tmp++; } } __ramfunc void SscHandler(void) { static UBYTE ByteCnt = 0; if (SoundSamplesLeft) { if (0 == CurrentFileFormat) { CalculateBitstream(SampleBuffer[SampleBufferNo],*pSoundPointer); *AT91C_SSC_TNPR = (unsigned int)SampleBuffer[SampleBufferNo]; *AT91C_SSC_TNCR = SAMPLEWORDS; pSoundPointer++; SoundSamplesLeft--; if (!SoundSamplesLeft) { pSoundPointer = pSoundPointerNext; SoundSamplesLeft = SoundSamplesLeftNext; *AT91C_SSC_CMR = ClockNext; SoundSamplesLeftNext = 0; } if (++SampleBufferNo >= SAMPLEBUFFERS) { SampleBufferNo = 0; } } else { if (0 == ByteCnt) { SoundADPCMDecoder(*pSoundPointer, Outdata, &State.Valprev, &State.Index); CalculateBitstream(SampleBuffer[SampleBufferNo],Outdata[0]); *AT91C_SSC_TNPR = (unsigned int)SampleBuffer[SampleBufferNo]; *AT91C_SSC_TNCR = SAMPLEWORDS; if (++SampleBufferNo >= SAMPLEBUFFERS) { SampleBufferNo = 0; } ByteCnt++; } else { CalculateBitstream(SampleBuffer[SampleBufferNo],Outdata[1]); *AT91C_SSC_TNPR = (unsigned int)SampleBuffer[SampleBufferNo]; *AT91C_SSC_TNCR = SAMPLEWORDS; pSoundPointer++; SoundSamplesLeft--; if (!SoundSamplesLeft) { pSoundPointer = pSoundPointerNext; SoundSamplesLeft = SoundSamplesLeftNext; *AT91C_SSC_CMR = ClockNext; SoundSamplesLeftNext = 0; } if (++SampleBufferNo >= SAMPLEBUFFERS) { SampleBufferNo = 0; } ByteCnt = 0; } } } else { if (ToneCycles) { ToneCycles--; if (ToneCycles < ToneCyclesReady) { SoundReady = TRUE; } *AT91C_SSC_TNPR = (unsigned int)ToneBuffer; *AT91C_SSC_TNCR = SAMPLETONENO; if (SoundDivider) { SOUNDEnable; } else { SOUNDDisable; } } else { SoundReady = TRUE; SOUNDDisable; SOUNDIntDisable; } } } UBYTE SoundStart(UBYTE *Sound,UWORD Length,UWORD SampleRate, UBYTE NewFileFormat) { UBYTE Result = FALSE; if (SoundReady == TRUE) { if (Length > 1) { CurrentFileFormat = NewFileFormat; *AT91C_SSC_CMR = SoundSampleRate(SampleRate); pSoundPointer = Sound; SoundSamplesLeft = Length; if (0 == CurrentFileFormat) { CalculateBitstream(SampleBuffer[0],*pSoundPointer); *AT91C_SSC_TPR = (unsigned int)SampleBuffer[0]; *AT91C_SSC_TCR = SAMPLEWORDS; pSoundPointer++; SoundSamplesLeft--; CalculateBitstream(SampleBuffer[1],*pSoundPointer); *AT91C_SSC_TNPR = (unsigned int)SampleBuffer[1]; *AT91C_SSC_TNCR = SAMPLEWORDS; pSoundPointer++; SoundSamplesLeft--; } else { State.Valprev = INIT_PREV_VAL_ADPCM; State.Index = INIT_INDEX_ADPCM; SoundADPCMDecoder(*pSoundPointer, Outdata, &State.Valprev, &State.Index); CalculateBitstream(SampleBuffer[0],Outdata[0]); *AT91C_SSC_TPR = (unsigned int)SampleBuffer[0]; *AT91C_SSC_TCR = SAMPLEWORDS; pSoundPointer++; SoundSamplesLeft--; CalculateBitstream(SampleBuffer[1],Outdata[1]); *AT91C_SSC_TNPR = (unsigned int)SampleBuffer[1]; *AT91C_SSC_TNCR = SAMPLEWORDS; } SampleBufferNo = 0; SoundReady = FALSE; SOUNDIntEnable; *AT91C_SSC_PTCR = AT91C_PDC_TXTEN; } Result = TRUE; } else { if (!ToneCycles) { if (!SoundSamplesLeftNext) { CurrentFileFormat = NewFileFormat; ClockNext = SoundSampleRate(SampleRate); pSoundPointerNext = Sound; SoundSamplesLeftNext = Length; Result = TRUE; } } } return (Result); } UBYTE SoundStop(void) { ToneCycles = 0; SOUNDIntDisable; SOUNDDisable; SoundReady = TRUE; SoundSamplesLeft = 0; SoundSamplesLeftNext = 0; MelodyPointer = 0; return (TRUE); } void SoundVolume(UBYTE Step) { if (Step > SOUNDVOLUMESTEPS) { Step = SOUNDVOLUMESTEPS; } SoundDivider = Step; } void SoundFreq(UWORD Freq,UWORD mS,UBYTE Step) { UBYTE Tmp; if (mS < DURATION_MIN) { mS = DURATION_MIN; } if (Freq) { if (Freq < FREQUENCY_MIN) { Freq = FREQUENCY_MIN; } if (Freq > FREQUENCY_MAX) { Freq = FREQUENCY_MAX; } if (Step > SOUNDVOLUMESTEPS) { Step = SOUNDVOLUMESTEPS; } } else { Step = 0; Freq = 1000; } SoundDivider = Step; SoundSamplesLeft = 0; SoundSamplesLeftNext = 0; for (Tmp = 0;Tmp < SAMPLETONENO;Tmp++) { ToneBuffer[Tmp] = TonePattern[Step][Tmp]; } *AT91C_SSC_CMR = (((ULONG)OSC / (2L * 512L)) / ((ULONG)Freq)) + 1L; ToneCycles = ((ULONG)Freq * (ULONG)mS) / 1000L - 1L; ToneCyclesReady = ((ULONG)Freq * (ULONG)2L) / 1000L + 1L; *AT91C_SSC_TNPR = (unsigned int)ToneBuffer; *AT91C_SSC_TNCR = SAMPLETONENO; *AT91C_SSC_PTCR = AT91C_PDC_TXTEN; SoundReady = FALSE; SOUNDIntEnable; } UBYTE SoundTone(UBYTE *pMel,UWORD Length,UBYTE Step) { UBYTE Result = FALSE; UWORD Freq; UWORD mS; if ((SoundReady == TRUE)) { if (MelodyPointer <= (Length - 4)) { Freq = (UWORD)pMel[MelodyPointer++] << 8; Freq += (UWORD)pMel[MelodyPointer++]; mS = (UWORD)pMel[MelodyPointer++] << 8; mS += (UWORD)pMel[MelodyPointer++]; SoundFreq(Freq,mS,Step); } else { MelodyPointer = 0; Result = TRUE; } } return (Result); } #define SOUNDInit {\ SOUNDIntDisable;\ SoundReady = TRUE;\ MelodyPointer = 0;\ *AT91C_PMC_PCER = (1L << AT91C_ID_SSC); /* Enable MCK clock */\ *AT91C_PIOA_PER = AT91C_PA17_TD; /* Disable TD on PA17 */\ *AT91C_PIOA_ODR = AT91C_PA17_TD;\ *AT91C_PIOA_OWDR = AT91C_PA17_TD;\ *AT91C_PIOA_MDDR = AT91C_PA17_TD;\ *AT91C_PIOA_PPUDR = AT91C_PA17_TD;\ *AT91C_PIOA_IFDR = AT91C_PA17_TD;\ *AT91C_PIOA_CODR = AT91C_PA17_TD;\ *AT91C_PIOA_IDR = AT91C_PA17_TD;\ *AT91C_SSC_CR = AT91C_SSC_SWRST;\ AT91C_AIC_SVR[AT91C_ID_SSC] = (unsigned int)SscHandler;\ AT91C_AIC_SMR[AT91C_ID_SSC] = AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED; /* Set priority */\ *AT91C_SSC_TCMR = AT91C_SSC_CKS_DIV + AT91C_SSC_CKO_CONTINOUS + AT91C_SSC_START_CONTINOUS;\ *AT91C_SSC_TFMR = (SAMPLEWORDBITS - 1) + ((SAMPLEWORDS & 0xF) << 8) + AT91C_SSC_MSBF;\ *AT91C_SSC_CR = AT91C_SSC_TXEN; /* TX enable */\ *AT91C_AIC_ICCR = (1L << AT91C_ID_SSC); /* Clear interrupt */\ *AT91C_AIC_IECR = (1L << AT91C_ID_SSC); /* Enable int. controller */\ } #define SOUNDVolume(V) SoundVolume((UBYTE)V) #define SOUNDReady SoundReady #define SOUNDStart(pSnd,Lng,SR,FT) SoundStart(pSnd,Lng,SR,FT) #define SOUNDStop SoundStop() #define SOUNDTone(pMel,Lng,Vol) SoundTone(pMel,Lng,Vol) #define SOUNDFreq(Freq,Duration,Vol) SoundFreq(Freq,Duration,Vol) #define SOUNDExit {\ SOUNDIntDisable;\ SOUNDDisable;\ *AT91C_AIC_IDCR = (1L << AT91C_ID_SSC);\ } #endif