198 lines
4.8 KiB
C
198 lines
4.8 KiB
C
/*
|
|
Hatari - ymFormat.c
|
|
|
|
This file is distributed under the GNU General Public License, version 2
|
|
or at your option any later version. Read the file gpl.txt for details.
|
|
|
|
YM File output, for use with STSound etc...
|
|
*/
|
|
const char YMFormat_fileid[] = "Hatari ymFormat.c : " __DATE__ " " __TIME__;
|
|
|
|
#include "main.h"
|
|
#include "configuration.h"
|
|
#include "file.h"
|
|
#include "log.h"
|
|
#include "psg.h"
|
|
#include "sound.h"
|
|
#include "ymFormat.h"
|
|
|
|
|
|
#define YM_MAX_VBLS (50*60*8) /* 50=1 second, 50*60=1 minute, 50*60*8=8 minutes, or 24000 */
|
|
#define YM_RECORDSIZE (4+(YM_MAX_VBLS*NUM_PSG_SOUND_REGISTERS)) /* ~330k for 8 minutes */
|
|
|
|
bool bRecordingYM = false;
|
|
static int nYMVBLS = 0;
|
|
static Uint8 *pYMData, *pYMWorkspace = NULL;
|
|
static char *pszYMFileName = NULL;
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Start recording YM registers to workspace
|
|
*/
|
|
bool YMFormat_BeginRecording(const char *filename)
|
|
{
|
|
/* Free any previous data, don't save */
|
|
bRecordingYM = false;
|
|
YMFormat_EndRecording();
|
|
|
|
/* Make sure we have a proper filename to use */
|
|
if (!filename || strlen(filename) <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
pszYMFileName = strdup(filename);
|
|
if (!pszYMFileName)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/* Create YM workspace */
|
|
pYMWorkspace = (Uint8 *)malloc(YM_RECORDSIZE);
|
|
|
|
if (!pYMWorkspace)
|
|
{
|
|
/* Failed to allocate memory, cannot record */
|
|
free(pszYMFileName);
|
|
pszYMFileName = NULL;
|
|
return false;
|
|
}
|
|
|
|
/* Get workspace pointer and store 4 byte header */
|
|
pYMData = pYMWorkspace;
|
|
*pYMData++ = 'Y';
|
|
*pYMData++ = 'M';
|
|
*pYMData++ = '3';
|
|
*pYMData++ = '!';
|
|
|
|
bRecordingYM = true; /* Ready to record */
|
|
nYMVBLS = 0; /* Number of VBLs of information */
|
|
|
|
/* And inform user */
|
|
Log_AlertDlg(LOG_INFO, "YM sound data recording has been started.");
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Convert YM data to stream for output
|
|
*
|
|
* Data is:
|
|
* 4 Byte header 'YM3!'
|
|
* VBL Count x 14 PSG registers
|
|
* BUT
|
|
* We need data in a register stream, eg Reg 0, VBL 1, VBL 2, VBL n and then next register...
|
|
*
|
|
* Convert to new workspace and return true if all OK.
|
|
*/
|
|
static bool YMFormat_ConvertToStreams(void)
|
|
{
|
|
Uint8 *pNewYMWorkspace;
|
|
Uint8 *pTmpYMData, *pNewYMData;
|
|
Uint8 *pTmpYMStream, *pNewYMStream;
|
|
int Reg, Count;
|
|
|
|
/* Allocate new workspace to convert data to */
|
|
pNewYMWorkspace = (Uint8 *)malloc(YM_RECORDSIZE);
|
|
if (pNewYMWorkspace)
|
|
{
|
|
/* Convert data, first copy over header */
|
|
pTmpYMData = pYMWorkspace;
|
|
pNewYMData = pNewYMWorkspace;
|
|
*pNewYMData++ = *pTmpYMData++;
|
|
*pNewYMData++ = *pTmpYMData++;
|
|
*pNewYMData++ = *pTmpYMData++;
|
|
*pNewYMData++ = *pTmpYMData++;
|
|
|
|
/* Now copy over each stream */
|
|
for(Reg=0; Reg<NUM_PSG_SOUND_REGISTERS; Reg++)
|
|
{
|
|
/* Get pointer to source / destination */
|
|
pTmpYMStream = pTmpYMData + Reg;
|
|
pNewYMStream = pNewYMData + (Reg*nYMVBLS);
|
|
|
|
/* Copy recording VBLs worth */
|
|
for(Count=0; Count<nYMVBLS; Count++)
|
|
{
|
|
*pNewYMStream++ = *pTmpYMStream;
|
|
pTmpYMStream += NUM_PSG_SOUND_REGISTERS;
|
|
}
|
|
}
|
|
|
|
/* Delete old workspace and assign new */
|
|
free(pYMWorkspace);
|
|
pYMWorkspace = pNewYMWorkspace;
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* End recording YM registers and save as '.YM' file
|
|
*/
|
|
void YMFormat_EndRecording(void)
|
|
{
|
|
/* Recording, have recorded information? */
|
|
if (bRecordingYM && pszYMFileName && pYMWorkspace && nYMVBLS)
|
|
{
|
|
/* Convert YM to correct format(list of register 1, then register 2...) */
|
|
if (YMFormat_ConvertToStreams())
|
|
{
|
|
/* Save YM File */
|
|
File_Save(pszYMFileName, pYMWorkspace,(size_t)(nYMVBLS*NUM_PSG_SOUND_REGISTERS)+4, false);
|
|
/* And inform user */
|
|
Log_AlertDlg(LOG_INFO, "YM sound data recording has been stopped.");
|
|
}
|
|
else
|
|
Log_AlertDlg(LOG_ERROR, "YM sound data conversion failed!");
|
|
|
|
}
|
|
/* And free */
|
|
if (pYMWorkspace)
|
|
{
|
|
free(pYMWorkspace);
|
|
pYMWorkspace = NULL;
|
|
}
|
|
if (pszYMFileName)
|
|
{
|
|
free(pszYMFileName);
|
|
pszYMFileName = NULL;
|
|
}
|
|
/* Stop recording */
|
|
bRecordingYM = false;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Store a VBLs worth of YM registers to workspace - call each VBL
|
|
*/
|
|
void YMFormat_UpdateRecording(void)
|
|
{
|
|
int i;
|
|
|
|
/* Can record this VBL information? */
|
|
if (bRecordingYM)
|
|
{
|
|
/* Copy VBL registers to workspace */
|
|
for(i=0; i<(NUM_PSG_SOUND_REGISTERS-1); i++)
|
|
*pYMData++ = SoundRegs[i];
|
|
/* Handle register '13'(PSG_REG_ENV_SHAPE) correctly - store 0xFF is did not write to this frame */
|
|
if (bEnvelopeFreqFlag)
|
|
*pYMData++ = SoundRegs[PSG_REG_ENV_SHAPE];
|
|
else
|
|
*pYMData++ = 0xff;
|
|
|
|
/* Increase VBL count */
|
|
nYMVBLS++;
|
|
/* If run out of workspace, just save */
|
|
if (nYMVBLS>=YM_MAX_VBLS)
|
|
YMFormat_EndRecording();
|
|
}
|
|
}
|
|
|