// // MODULE : STAUDIO.C // PURPOSE : Audio Routines // AUTHOR : JBS Yadawa // CREATED : 7/20/96 // // // Copyright (C) 1996 SGS-THOMSON Microelectronics // // // REVISION HISTORY : // // DATE : // // COMMENTS : // #include "common.h" #include "stdefs.h" #include "staudio.h" #include "debug.h" #include "error.h" #include "board.h" #include "sti3520A.h" #include /////////// static PAUDIO pAudio; #define SLOW_MODE 0 #define PLAY_MODE 1 #define FAST_MODE 2 #define IT_A 0 // interrupt detected void AudioOpen(PAUDIO pAud) { pAudio = pAud; pAudio->AudioState = AUDIO_POWER_UP; pAudio->IntAudio = NO_IT_A; pAudio->MaskItAudio = 0; pAudio->ErrorMsg = NO_ERROR; pAudio->FirstPTS = FALSE; // First PTS not reached yet pAudio->mute = FALSE; pAudio->Stepped = FALSE; pAudio->FrameCount = 0; } void AudioClose(void) { } void AudioInitDecoder(WORD StreamType) { /* #if 0 pAudio->StrType = StreamType; switch(pAudio->AudioState) { case AUDIO_POWER_UP: BoardWriteAudio(RESET, 1); // reset the decoder //ALTERAClearPendingAudioIT(); // Clear pending audio interrupt generated by soft reset BoardWriteAudio(INTR_EN, 0); // disable all interupts BoardWriteAudio(INTR_EN + LSB, 0); BoardWriteAudio(PLAY, 0); // disable play output BoardWriteAudio(MUTE, 0); // do not mute output. LRclk and Sclk Stopped here BoardWriteAudio(INVERT_SCLK, 0); // standard BoardWriteAudio(INVERT_LRCLK, 1);// standard #ifndef VALID3520 //************************************************************** // Philips TDA1311 is a 16 bit DAC (oversampling 1x, 2x, 4x, 8x) // -> LRCLK = SCLK / 32 // -> SCLK = PCMCLK / 8 (8 times oversampling => PCM_DIV = 3) // => PCMCLK = 256 * Sampling Frequency //************************************************************** BoardWriteAudio(PCM_DIV, 3); BoardWriteAudio(PCM_ORD, 0); // MSB first BoardWriteAudio(PCM_18, 0); // 16 bits of PCM data BoardWriteAudio(FORMAT, 0); // I2S output format BoardWriteAudio(DIF, 0); // Optionnal in 16 bit output #else //************************************************************** // Crystal CS4330 is an 18 bit DAC (oversampling 1x, 4x, 6x, 8x) // -> LRCLK = SCLK / 64 // -> SCLK = PCMCLK / 4 (4 times oversampling => PCM_DIV = 1) // => PCMCLK = 256 * Sampling Frequency //************************************************************** BoardWriteAudio(PCM_DIV, 1); BoardWriteAudio(PCM_ORD, 0); BoardWriteAudio(PCM_18, 1); // 18 bits of PCM data BoardWriteAudio(FORMAT, 0); // I2S output format BoardWriteAudio(DIF, 0); // Optionnal in 16 bit #endif BoardWriteAudio(STR_SEL, 0); // Default Stream Type is audio elem stream BoardWriteAudio(CRC_ECM, 1); // mute on CRC error correction BoardWriteAudio(SYNC_ECM, 1); // mute if Sync lost BoardWriteAudio(SYNCHRO_CONFIRM, 1); // synchro confirmation mode BoardWriteAudio(SYNC_REG, 0x3F); // layer, bitrate, fs fields not used BoardWriteAudio(PACKET_SYNC_CHOICE, 0);// multiplexed stream BoardWriteAudio(LATENCY, 0x0); // Low Lattency decoding BoardWriteAudio(SYNC_LCK, 0x2); // locked after 2 good Sync BoardWriteAudio(SIN_EN, 0x01); // Serial data input to enable bit buffer access BoardWriteAudio(AUDIO_ID_EN, 0x0);// ignore audio stream ID BoardWriteAudio(AUDIO_ID, 0x0); // audio stream ID ignored BoardWriteAudio(FREE_FORM_H, 0x0);// not free format BoardWriteAudio(FREE_FORM_L, 0x0); BoardWriteAudio(DUAL_REG, 0); // Select Stereo Mode AudioSetSTCParameters(44100UL); BoardAudioSetSamplingFrequency(44100UL); pAudio->FrameCount = 0; // Reset Frame Count. pAudio->AudioState = AUDIO_INIT; break; default: break; } #else BoardWriteAudio(0xF0, 1); // reset the decoder BoardWriteAudio(0xC6, 0); BoardWriteAudio(0xEF, 1); BoardWriteAudio(PCM_DIV, 2); BoardWriteAudio(0x9f, 0); BoardWriteAudio(0x99, 0); BoardWriteAudio(0xB6, 3); BoardWriteAudio(0x9e, 0); BoardWriteAudio(0xa0, 0); BoardWriteAudio(0x91, 0); BoardWriteAudio(0xb8, 0); BoardWriteAudio(0x96, 1); BoardWriteAudio(0xd3, 0); BoardWriteAudio(0xac, 0); BoardWriteAudio(0xc4, 0); BoardWriteAudio(0xc2, 1); BoardWriteAudio(0xAE, 1); #endif */ } WORD AudioTestReg(void) { #if 0 WORD ReadValue; BoardWriteAudio(ATTEN_L, 0x55); BoardWriteAudio(ATTEN_R, 0xAA); ReadValue = BoardReadAudio(ATTEN_L); if ((ReadValue & 0x3F) != 0x15) goto Error; ReadValue = BoardReadAudio(ATTEN_R); if ((ReadValue & 0x3F) != 0x2A) goto Error; return NO_ERROR; Error : SetErrorCode(ERR_AUDIO_REG_TEST_FAILED); return BAD_REG_A; #else return NO_ERROR; #endif } WORD AudioTest(void) { #if 0 WORD TestResult; TestResult = AudioTestReg(); if (TestResult != NO_ERROR) return TestResult; else { #ifdef DOSAPP if (AudioTestInt(pAudio) == NO_IT_A) return NO_IT_A; else #endif return NO_ERROR; } #else return NO_ERROR; #endif } WORD AudioTestInt(void) { WORD err = NO_ERROR; #if 0 U8 Threshold; WORD a = 0; pAudio->MaskItAudio = FIFT; Threshold = BoardReadAudio(FIFO_IN_TRESHOLD); //---- Configure audio BoardWriteAudio(PLAY, 0x00); BoardWriteAudio(FIFO_IN_TRESHOLD, 0x01); //---- Enable FIFO full interrupt BoardWriteAudio(INTR_EN, 0x00); BoardWriteAudio(INTR_EN + LSB, 0x10); //---- Write a byte to force an interrupt BoardWriteAudio(DATA_IN, 0x00); // wait for occurrence of first audio interrupt while (pAudio->IntAudio == NO_IT_A) { Delay(1000); a++; /* incremented every 1 ms */ if (a >= 1000) { DPF((Trace, "AudioTestInt failed !!")); SetErrorCode(ERR_NO_AUDIO_INTR); err = NO_IT_A; /* No interrupt */ break; } } // Restore Interrupt mask pAudio->MaskItAudio = 0; AudioMaskInt(); BoardWriteAudio(FIFO_IN_TRESHOLD, Threshold); BoardReadAudio(INTR); /* to clear audio interrupts flags */ #endif return err; } // Set the decoding mode and parameters void AudioSetMode(WORD Mode, WORD param) { #if 0 pAudio->DecodeMode = Mode; switch (pAudio->DecodeMode) { case PLAY_MODE: BoardWriteAudio(MUTE, 0); pAudio->fastForward = 0; pAudio->decSlowDown = 0; break; case FAST_MODE: pAudio->fastForward = 1; pAudio->decSlowDown = 0; break; case SLOW_MODE: pAudio->fastForward = 0; pAudio->decSlowDown = param; break; } #endif } // Decode void AudioDecode(void) { #if 0 switch (pAudio->AudioState) { case AUDIO_POWER_UP: break; case AUDIO_INIT: // Change in synchro + buffer over BALF +PTS pAudio->MaskItAudio = SYNC|BOF|PCMU|CRC| PTS; BoardWriteAudio(INTR_EN, (BYTE)(pAudio->MaskItAudio & 0xFF)); BoardWriteAudio(INTR_EN + LSB, (BYTE)(pAudio->MaskItAudio >> 8 )); //yg BoardWriteAudio(MUTE, 1); // This Starts SClk and LRClk outputs BoardWriteAudio(PLAY, 1); // Start decoding Output is Mute pAudio->AudioState = AUDIO_STC_INIT; break; case AUDIO_STC_INIT: pAudio->AudioState = AUDIO_DECODE; BoardWriteAudio(PLAY, 1); // Restart decoding (decoding had been stopped when first audio PTS detected) BoardWriteAudio(MUTE, 0); // Stop Muting output break; case AUDIO_DECODE: break; case AUDIO_PAUSE: case AUDIO_STEP: BoardWriteAudio(PLAY, 1); BoardWriteAudio(MUTE, 0); pAudio->AudioState = AUDIO_DECODE; break; } #endif } void AudioStep(void) { #if 0 BoardWriteAudio(MUTE, 0); BoardWriteAudio(PLAY, 1); pAudio->AudioState = AUDIO_STEP; pAudio->Stepped = FALSE; #endif } void AudioStop(void) { #if 0 switch(pAudio->AudioState) { case AUDIO_POWER_UP: break; case AUDIO_INIT: break; case AUDIO_STC_INIT: case AUDIO_DECODE: pAudio->AudioState = AUDIO_POWER_UP; AudioInitDecoder(pAudio, pAudio->StrType); break; } #endif } void AudioPause(void) { #if 0 switch(pAudio->AudioState) { case AUDIO_POWER_UP: /* After reset */ case AUDIO_INIT: /* Initialisation + test of the decoders */ case AUDIO_STC_INIT: /* STC of audio decoder initialized */ case AUDIO_DECODE: /* Normal decode */ BoardWriteAudio(MUTE, 1); BoardWriteAudio(PLAY, 0); pAudio->AudioState = AUDIO_PAUSE; break; } #endif } WORD AudioGetState(void) { return ( pAudio->AudioState); } void AudioSetSTCParameters(DWORD SampFreq) { #if 0 // Note : // STCCLK = PCMCLK (fixed inside STi3520A) // (PCMCLK * inc) / div = 90kHz switch(SampFreq){ case 32000UL: // PCMCLK = 256 * 32 = 8192 kHz, inc = 45, div = 4096 -> 90kHz BoardWriteAudio(STC_INC, 45); BoardWriteAudio(STC_DIVH, 0x10); BoardWriteAudio(STC_DIVL, 0x00); break; case 44100UL: // PCMCLK = 256 * 44.1 = 11289.6 kHz, inc = 25, div = 3136 -> 90kHz BoardWriteAudio(STC_INC, 25); BoardWriteAudio(STC_DIVH, 0x0C); BoardWriteAudio(STC_DIVL, 0x40); break; case 48000UL: // PCMCLK = 256 * 48 = 12288 kHz, inc = 15, div = 2048 -> 90kHz BoardWriteAudio(STC_INC, 15); BoardWriteAudio(STC_DIVH, 0x08); BoardWriteAudio(STC_DIVL, 0x00); break; default : break; } BoardWriteAudio(STC_CTL, 0x40); // Load STC_VID on rising edge of VSYNC #endif } DWORD AudioGetSTC(void) { #if 0 DWORD stc; WORD j; BoardWriteAudio(STC_CTL, 0x44); // load current STC value to STC for ( j = 0; j < 0xF; j++) ; stc = ( BoardReadAudio(STC_3 ) & 0xFFL ) << 24; stc = stc | ( ( BoardReadAudio(STC_2 ) & 0xFFL ) << 16); stc = stc | ( ( BoardReadAudio(STC_1 ) & 0xFFL ) << 8); stc = stc | ( BoardReadAudio(STC_0 ) & 0xFFL); return ( stc); #else return 0; #endif } DWORD AudioGetVideoSTC(void) { #if 0 DWORD stc; WORD j; BoardWriteAudio(STC_CTL, 0x48); // load STC_VID to STC, Mode 0 mapping // BoardWriteAudio(STC_CTL, 0x44); accu // BoardWriteAudio(STC_CTL, 0x50); for ( j = 0; j < 0xF; j++) ; /* stc = ( BoardReadAudio(STC_3 ) & 0xFFL ) << 24; stc = stc | ((BoardReadAudio(STC_2) & 0xFFL ) << 16); stc = stc | ((BoardReadAudio(STC_1) & 0xFFL ) << 8); stc = stc | ((BoardReadAudio(STC_0) & 0xFFL )); */ stc = ( BoardReadAudio(STC_0) & 0xFFL ) << 0; stc = stc | ((BoardReadAudio(STC_1) & 0xFFL ) << 8); stc = stc | ((BoardReadAudio(STC_2) & 0xFFL ) << 16); stc = stc | ((BoardReadAudio(STC_3) & 0xFFL ) << 24); return stc; #else return 0; #endif } void AudioInitSTC(DWORD stc) { #if 0 BoardWriteAudio(STC_0, (U8)(stc & 0xFFL)); stc >>= 8; BoardWriteAudio(STC_1, (U8)(stc & 0xFFL)); stc >>= 8; BoardWriteAudio(STC_2, (U8)(stc & 0xFFL)); stc >>= 8; BoardWriteAudio(STC_3, (U8)(stc & 0xFFL)); BoardWriteAudio(STC_CTL, 0x41); // load STC to accumulator, #endif } DWORD AudioGetPTS(void) { return pAudio->PtsAudio; } WORD AudioGetErrorMsg(void) { return pAudio->ErrorMsg; } void AudioSetRightVolume(WORD volume) { #if 0 BoardWriteAudio(ATTEN_R, (BYTE)volume); #endif } void AudioSetLeftVolume(WORD volume) { #if 0 BoardWriteAudio(ATTEN_L, (BYTE)volume); #endif } void AudioMute(void) { #if 0 if (pAudio->mute) { BoardWriteAudio(MUTE, 0); pAudio->mute = FALSE; } else { BoardWriteAudio(MUTE, 1); pAudio->mute = TRUE; } #endif } BOOL AudioIsFirstPTS(void) { return pAudio->FirstPTS; } void AudioSetStreamType(WORD StrType) { #if 0 BoardWriteAudio(STR_SEL, (BYTE)StrType); #endif } void AudioInitPesParser (WORD StreamType) { #if 0 switch(StreamType) { case SYSTEM_STREAM: case VIDEO_PACKET: case AUDIO_PACKET: case VIDEO_PES: case AUDIO_PES: BoardWriteAudio( STR_SEL, 1); break; case DUAL_PES: BoardWriteAudio( STR_SEL, 4); break; case DUAL_ES: BoardWriteAudio( STR_SEL, 0); break; case VIDEO_STREAM: case AUDIO_STREAM: BoardWriteAudio( STR_SEL, 0); break; } #endif } void AudioMaskInt(void) { #if 0 BoardWriteAudio(INTR_EN, 0); BoardWriteAudio(INTR_EN + LSB, 0); #endif } void AudioRestoreInt(void) { #if 0 //HostDisplay(DISPLAY_FASTEST, "!%x!", pAudio->MaskItAudio); BoardWriteAudio(INTR_EN, (BYTE)(pAudio->MaskItAudio & 0xFF)); BoardWriteAudio(INTR_EN + LSB, (BYTE)(pAudio->MaskItAudio >> 8)); #endif } BOOL AudioAudioInt(void) { #if 0 WORD int_stat_reg, i; BOOLEAN bAudioIntr = FALSE; // Read the interrupt status register int_stat_reg = BoardReadAudio(INTR); i = BoardReadAudio(INTR + LSB); i = i << 8; int_stat_reg = ( int_stat_reg & 0xFF ) | i; int_stat_reg = int_stat_reg & pAudio->MaskItAudio; /* Mask the IT not used */ if(int_stat_reg) bAudioIntr = TRUE; /******************************************************/ /** FIFO FULL used to test audio interrupt generation**/ /******************************************************/ if (int_stat_reg & FIFT) { pAudio->IntAudio = IT_A; } /******************************************************/ /** CHANGE SYNCHRO **/ /******************************************************/ if (int_stat_reg & SYNC) { i = BoardReadAudio(SYNC_ST); // Synchronization status if ((i & 0x3) == 3) { // Locked // Disable Change in synchro pAudio->MaskItAudio = pAudio->MaskItAudio & NSYNC; // Next Interrupt should be change in sampling freq pAudio->MaskItAudio = pAudio->MaskItAudio | SAMP; } } /******************************************************/ /** CHANGE IN SAMPLING FREQUENCY **/ /******************************************************/ if (int_stat_reg & SAMP) { i = BoardReadAudio(PCM_FS ) & 0x3; // Get Sampling frequency switch(i) { case 0 : BoardAudioSetSamplingFrequency(44100UL); AudioSetSTCParameters(44100UL); break; case 1 : BoardAudioSetSamplingFrequency(48000UL); AudioSetSTCParameters(48000UL); break; case 2 : BoardAudioSetSamplingFrequency(32000UL); AudioSetSTCParameters(32000UL); break; default : break; } // Disable change in sampling frequency pAudio->MaskItAudio = pAudio->MaskItAudio & NSAMP; } /******************************************************/ /** CRC error **/ /******************************************************/ if (int_stat_reg & CRC) { } /******************************************************/ /** PCM Underflow **/ /******************************************************/ if (int_stat_reg & PCMU) { } /******************************************************/ /** Begining of Frame **/ /******************************************************/ if (int_stat_reg & BOF) { DWORD STC = AudioGetVideoSTC(); static DWORD STCOld; // HostDisplay(DISPLAY_FASTEST, "STCBOF = %8lu D = %5ld\r\n", STC, STC - STCOld); // STCOld = STC; // Check if stepping if ((pAudio->AudioState == AUDIO_STEP) && (pAudio->Stepped == FALSE)) { BoardWriteAudio(MUTE, 1); BoardWriteAudio(PLAY, 0); pAudio->Stepped = TRUE; } // If Slow motion or Fast forward, Mute Audio if ( pAudio->DecodeMode != PLAY_MODE ) { BoardWriteAudio(MUTE, 1); pAudio->mute = TRUE; if ((pAudio->FrameCount % 4) && (pAudio->fastForward)) BoardWriteAudio(SKIP, 1); else if ((pAudio->DecodeMode == SLOW_MODE ) && ((pAudio->FrameCount % (pAudio->decSlowDown + 1)) != 0)) BoardWriteAudio(REPEAT, 1); } pAudio->FrameCount++; // Increment Frame Count } /******************************************************/ /** PTS detected **/ /******************************************************/ if ( int_stat_reg & PTS ) { DWORD pts; //DBG1('p'); /* BoardReadAudio(PTS_4); // To clear pts interrupt pts = (BoardReadAudio(PTS_3) & 0xFFL) << 24; pts = pts | ((BoardReadAudio(PTS_2 ) & 0xFFL) << 16); pts = pts | ((BoardReadAudio(PTS_1 ) & 0xFFL) << 8); pts = pts | ( BoardReadAudio(PTS_0 ) & 0xFFL); */ pts = (BoardReadAudio(PTS_0) & 0xFFL) << 0; pts = pts | ((BoardReadAudio(PTS_1) & 0xFFL) << 8); pts = pts | ((BoardReadAudio(PTS_2) & 0xFFL) << 16); pts = pts | ((BoardReadAudio(PTS_3) & 0xFFL) << 24); BoardReadAudio(PTS_4); // To clear pts interrupt pAudio->PtsAudio = pts; if (pAudio->AudioState == AUDIO_STC_INIT) { pAudio->FirstPTS = TRUE; //yg BoardWriteAudio(PLAY, 0); } if (pAudio->AudioState == AUDIO_DECODE) { // HostDirectPutChar('P', BLACK, LIGHTBLUE); AudioInitSTC ( pts); // DWORD STC = AudioGetVideoSTC(); // HostDisplay(DISPLAY_FASTEST, "STC = %8lu PTSA = %8lu D = %8ld\r\n", STC, pts, STC - pts); } } return bAudioIntr; #else return FALSE; #endif }