aboutsummaryrefslogtreecommitdiff
path: root/AT91SAM7S256/Source/d_sound.r
diff options
context:
space:
mode:
Diffstat (limited to 'AT91SAM7S256/Source/d_sound.r')
-rw-r--r--AT91SAM7S256/Source/d_sound.r514
1 files changed, 514 insertions, 0 deletions
diff --git a/AT91SAM7S256/Source/d_sound.r b/AT91SAM7S256/Source/d_sound.r
new file mode 100644
index 0000000..00c7511
--- /dev/null
+++ b/AT91SAM7S256/Source/d_sound.r
@@ -0,0 +1,514 @@
+//
+// Programmer
+//
+// Date init 14.12.2004
+//
+// Reviser $Author:: Dkflebun $
+//
+// Revision date $Date:: 5-02-07 13:36 $
+//
+// Filename $Workfile:: d_sound.r $
+//
+// Version $Revision:: 34 $
+//
+// Archive $Archive:: /LMS2006/Sys01/Main/Firmware/Source/d_sound.r $
+//
+// 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
+ }
+};
+
+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