thug/Code/Gel/Movies/Ngps/audiodec.cpp

484 lines
12 KiB
C++
Raw Normal View History

2016-02-13 21:39:12 +00:00
#include <eekernel.h>
#include <stdio.h>
#include <string.h>
#include <sif.h>
#include <sifdev.h>
#include <libsdr.h>
#include <sdrcmd.h>
#include "sys/config/config.h"
#include "gel/movies/ngps/defs.h"
#include "gel/movies/ngps/audiodec.h"
#include "gel/movies/ngps/p_movies.h"
#include "gel/music/music.h"
#include "gel/soundfx/soundfx.h"
#define AU_HEADER_SIZE 40
#define UNIT_SIZE 1024
#define PRESET_VALUE(count) (count)
namespace Flx
{
#define MAX_VOL ( ( float ) 0x3fff )
static void iopGetArea(int *pd0, int *d0, int *pd1, int *d1,
AudioDec *ad, int pos);
static int sendToIOP2area(int pd0, int d0, int pd1, int d1,
u_char *ps0, int s0, u_char *ps1, int s1);
static int sendToIOP(int dst, u_char *src, int size);
//static void changeMasterVolume(u_int val);
static void changeInputVolume(u_int val);
void SetMovieVolume( void )
{
// ///////////////////////////////////////
//
// Change input volume
//
Sfx::CSfxManager * sfx_manager = Sfx::CSfxManager::Instance();
float musicVol = Pcm::GetVolume( ) * Config::GetMasterVolume()/100.0f;
float sfxVol = sfx_manager->GetMainVolume( ) * Config::GetMasterVolume()/100.0f;
float vol = musicVol > sfxVol ? musicVol : sfxVol;
int inputVol = ( int ) ( ( vol * MAX_VOL ) / 100.0f );
changeInputVolume( inputVol );
}
// ////////////////////////////////////////////////////////////////
//
// Create audio decoder
//
int audioDecCreate(
AudioDec *ad,
u_char *buff,
int buffSize,
int iopBuffSize,
int pIopBuff
)
{
SetMovieVolume( );
ad->state = AU_STATE_INIT;
ad->hdrCount = 0;
ad->data = buff;
ad->put = 0;
ad->count = 0;
ad->size = buffSize;
ad->totalBytes = 0;
ad->totalBytesSent = 0;
ad->iopBuffSize = iopBuffSize;
ad->iopLastPos = 0;
ad->iopPausePos = 0;
// ///////////////////////////////////////
//
// Audio data buffer on IOP
//
ad->iopBuff = pIopBuff; //(int)sceSifAllocIopHeap(iopBuffSize);
if(ad->iopBuff < 0) {
printf( "Cannot allocate IOP memory\n");
return 0;
}
printf("IOP memory 0x%08x(size:%d) is allocated\n",
ad->iopBuff, iopBuffSize);
// ///////////////////////////////////////
//
// Zero data buffer on IOP
//
ad->iopZero = pIopBuff + iopBuffSize; //(int)sceSifAllocIopHeap(ZERO_BUFF_SIZE);
if(ad->iopZero < 0) {
printf( "Cannot allocate IOP memory\n");
return 0;
}
printf("IOP memory 0x%08x(size:%d) is allocated\n",
ad->iopZero, ZERO_BUFF_SIZE);
// send zero data to IOP
memset ( MOVIE_MEM_PTR _0_buf, 0, ZERO_BUFF_SIZE);
sendToIOP(ad->iopZero, ( u_char * ) MOVIE_MEM_PTR _0_buf, ZERO_BUFF_SIZE);
// ///////////////////////////////////////
//
// Change master volume
//
// changeMasterVolume(0x3fff);
return 1;
}
// ////////////////////////////////////////////////////////////////
//
// Delete audio decoder
//
int audioDecDelete(AudioDec *ad)
{
// sceSifFreeIopHeap((void *)ad->iopBuff);
// sceSifFreeIopHeap((void *)ad->iopZero);
// ///////////////////////////////////////
//
// Change master volume
//
// changeMasterVolume(0x0000);
changeInputVolume(0x0000);
return 1;
}
// ////////////////////////////////////////////////////////////////
//
// Pause
//
void audioDecPause(AudioDec *ad)
{
int ret;
ad->state = AU_STATE_PAUSE;
// ///////////////////////////////////////
//
// Change input volume
//
changeInputVolume(0x0000);
// ///////////////////////////////////////
//
// Stop DMA and save the position to be played
//
ret = sceSdRemote(1, rSdBlockTrans, AUTODMA_CH,
SD_TRANS_MODE_STOP, NULL, 0) & 0x00FFFFFF;
ad->iopPausePos = ret - ad->iopBuff;
// ///////////////////////////////////////
//
// Clear SPU2 buffer
//
sceSdRemote(1, rSdVoiceTrans, AUTODMA_CH,
SD_TRANS_MODE_WRITE | SD_TRANS_BY_DMA,
ad->iopZero, 0x4000, ZERO_BUFF_SIZE);
}
// ////////////////////////////////////////////////////////////////
//
// Resume
//
void audioDecResume(AudioDec *ad)
{
SetMovieVolume( );
sceSdRemote(1, rSdBlockTrans, AUTODMA_CH,
(SD_TRANS_MODE_WRITE_FROM | SD_BLOCK_LOOP),
ad->iopBuff, (ad->iopBuffSize/UNIT_SIZE)*UNIT_SIZE,
ad->iopBuff + ad->iopPausePos);
ad->state = AU_STATE_PLAY;
}
// ////////////////////////////////////////////////////////////////
//
// Start to play audio data
//
void audioDecStart(AudioDec *ad)
{
// return audioDecResume(ad);
audioDecResume(ad);
}
// ////////////////////////////////////////////////////////////////
//
// Re-initialize audio decoder
//
void audioDecReset(AudioDec *ad)
{
// ///////////////////////////////////////
//
// Stop audio
//
audioDecPause(ad);
ad->state = AU_STATE_INIT;
ad->hdrCount = 0;
ad->put = 0;
ad->count = 0;
ad->totalBytes = 0;
ad->totalBytesSent = 0;
ad->iopLastPos = 0;
ad->iopPausePos = 0;
}
// ////////////////////////////////////////////////////////////////
//
// Get empty areas
//
void audioDecBeginPut(AudioDec *ad,
u_char **ptr0, int *len0, u_char **ptr1, int *len1)
{
int len;
// ///////////////////////////////////////
//
// return ADS header area when (state == AU_STATE_INIT)
//
if (ad->state == AU_STATE_INIT) {
*ptr0 = (u_char*)&ad->sshd + ad->hdrCount;
*len0 = AU_HDR_SIZE - ad->hdrCount;
*ptr1 = (u_char*)ad->data;
*len1 = ad->size;
return;
}
// ///////////////////////////////////////
//
// Return the empty areas
//
len = ad->size - ad->count;
if (ad->size - ad->put >= len) { // area0
*ptr0 = ad->data + ad->put;
*len0 = len;
*ptr1 = NULL;
*len1 = 0;
} else { // area0 + area1
*ptr0 = ad->data + ad->put;
*len0 = ad->size - ad->put;
*ptr1 = ad->data;
*len1 = len - (ad->size - ad->put);
}
}
// ////////////////////////////////////////////////////////////////
//
// Update pointer
//
void audioDecEndPut(AudioDec *ad, int size)
{
if (ad->state == AU_STATE_INIT) {
int hdr_add = min( size, AU_HDR_SIZE - ( int )ad->hdrCount);
ad->hdrCount += hdr_add;
if ( ( int ) ad->hdrCount >= AU_HDR_SIZE) {
ad->state = AU_STATE_PRESET;
printf("-------- audio information --------------------\n");
printf("[%c%c%c%c]\n"
"header size: %d\n"
"type(0:PCM big, 1:PCM little, 2:ADPCM): %d\n"
"sampling rate: %dHz\n"
"channels: %d\n"
"interleave size: %d\n"
"interleave start block address: %d\n"
"interleave end block address: %d\n",
ad->sshd.id[0],
ad->sshd.id[1],
ad->sshd.id[2],
ad->sshd.id[3],
ad->sshd.size,
ad->sshd.type,
ad->sshd.rate,
ad->sshd.ch,
ad->sshd.interSize,
ad->sshd.loopStart,
ad->sshd.loopEnd
);
printf("[%c%c%c%c]\n"
"data size: %d\n",
ad->ssbd.id[0],
ad->ssbd.id[1],
ad->ssbd.id[2],
ad->ssbd.id[3],
ad->ssbd.size
);
}
size -= hdr_add;
}
ad->put = (ad->put + size) % ad->size;
ad->count += size;
ad->totalBytes += size;
}
// ////////////////////////////////////////////////////////////////
//
// Check to see if enough data is already sent to IOP or not
//
int audioDecIsPreset(AudioDec *ad)
{
return ad->totalBytesSent >= PRESET_VALUE(ad->iopBuffSize);
}
// ////////////////////////////////////////////////////////////////
//
// Send data to IOP
//
int audioDecSendToIOP(AudioDec *ad)
{
int pd0, pd1, d0, d1;
u_char *ps0, *ps1;
int s0, s1;
int count_sent = 0;
int countAdj;
int pos = 0;
switch (ad->state) {
case AU_STATE_INIT:
return 0;
break;
case AU_STATE_PRESET:
pd0 = ad->iopBuff + (ad->totalBytesSent) % ad->iopBuffSize;
d0 = ad->iopBuffSize - ad->totalBytesSent;
pd1 = 0;
d1 = 0;
break;
case AU_STATE_PLAY:
pos = ((sceSdRemote(1, rSdBlockTransStatus, AUTODMA_CH)
& 0x00FFFFFF) - ad->iopBuff);
iopGetArea(&pd0, &d0, &pd1, &d1, ad, pos);
break;
case AU_STATE_PAUSE:
return 0;
break;
}
ps0 = ad->data + (ad->put - ad->count + ad->size) % ad->size;
ps1 = ad->data;
// adjust to UNIT_SIZE boundary
countAdj = (ad->count / UNIT_SIZE) * UNIT_SIZE;
s0 = min(ad->data + ad->size - ps0, countAdj);
s1 = countAdj - s0;
if (d0 + d1 >= UNIT_SIZE && s0 + s1 >= UNIT_SIZE) {
count_sent = sendToIOP2area(pd0, d0, pd1, d1, ps0, s0, ps1, s1);
}
ad->count -= count_sent;
ad->totalBytesSent += count_sent;
ad->iopLastPos = (ad->iopLastPos + count_sent) % ad->iopBuffSize;
return count_sent;
}
// ////////////////////////////////////////////////////////////////
//
// Get empty area of IOP audio buffer
//
static void iopGetArea(int *pd0, int *d0, int *pd1, int *d1,
AudioDec *ad, int pos)
{
int len = (pos + ad->iopBuffSize - ad->iopLastPos - UNIT_SIZE)
% ad->iopBuffSize;
// adjust to UNIT_SIZE boundary
len = (len / UNIT_SIZE) * UNIT_SIZE;
if (ad->iopBuffSize - ad->iopLastPos >= len) { // area0
*pd0 = ad->iopBuff + ad->iopLastPos;
*d0 = len;
*pd1 = 0;
*d1 = 0;
} else { // area0 + area1
*pd0 = ad->iopBuff + ad->iopLastPos;
*d0 = ad->iopBuffSize - ad->iopLastPos;
*pd1 = ad->iopBuff;
*d1 = len - (ad->iopBuffSize - ad->iopLastPos);
}
}
// ////////////////////////////////////////////////////////////////
//
// Send data to IOP
//
static int sendToIOP2area(int pd0, int d0, int pd1, int d1,
u_char *ps0, int s0, u_char *ps1, int s1)
{
if (d0 + d1 < s0 + s1) {
int diff = (s0 + s1) - (d0 + d1);
if (diff >= s1) {
s0 -= (diff - s1);
s1 = 0;
} else {
s1 -= diff;
}
}
//
// (d0 + d1 >= s0 + s1)
//
if (s0 >= d0) {
sendToIOP(pd0, ps0, d0);
sendToIOP(pd1, ps0 + d0, s0 - d0);
sendToIOP(pd1 + s0 - d0, ps1, s1);
} else { // s0 < d0
if (s1 >= d0 - s0) {
sendToIOP(pd0, ps0, s0);
sendToIOP(pd0 + s0, ps1, d0 - s0);
sendToIOP(pd1, ps1 + d0 - s0, s1 - (d0 - s0));
} else { // s1 < d0 - s0
sendToIOP(pd0, ps0, s0);
sendToIOP(pd0 + s0, ps1, s1);
}
}
return s0 + s1;
}
// ////////////////////////////////////////////////////////////////
//
// Send data to IOP
//
static int sendToIOP(int dst, u_char *src, int size)
{
sceSifDmaData transData;
int did;
if (size <= 0) {
return 0;
}
transData.data = (u_int)src;
transData.addr = (u_int)dst;
transData.size = size;
transData.mode = 0; // caution
FlushCache(0);
did = sceSifSetDma( &transData, 1 );
while (sceSifDmaStat(did) >= 0)
;
return size;
}
// ////////////////////////////////////////////////////////////////
//
// Change master volume
//
/*
static void changeMasterVolume(u_int val)
{
int i;
for( i = 0; i < 2; i++ ) {
sceSdRemote(1, rSdSetParam, i | SD_P_MVOLL, val);
sceSdRemote(1, rSdSetParam, i | SD_P_MVOLR, val);
}
} */
// ////////////////////////////////////////////////////////////////
//
// Change input volume
//
static void changeInputVolume(u_int val)
{
sceSdRemote(1, rSdSetParam, AUTODMA_CH | SD_P_BVOLL, val);
sceSdRemote(1, rSdSetParam, AUTODMA_CH | SD_P_BVOLR, val);
}
} // namespace Flx