Files
sibo-playground/code/SIBOSDK/record/wvefile.c
T
2026-07-06 18:01:36 +01:00

191 lines
6.0 KiB
C

/*
WVEFILE.C
Sound record/playback sound file
*/
#include <p_std.h>
#include <p_gen.h>
#include <p_que.h>
#include <p_object.h>
#include <p_file.h>
#include <wlib.h>
#include <hwim.h>
#include <record.g>
LOCAL_C ULONG SamplesToTenths(ULONG samples)
{
return((samples>>4)/50);
}
LOCAL_C ULONG EffectiveSamples(ULONG samples)
/*
Converts the number of byte samples to the effective number of
samples for playback by rounding up to the nearest 0x800 (2K)
boundary and adding another 0x600.
*/
{
return(((samples+0x7ff)&(~0x7ff))+0x600);
}
LOCAL_C VOID CloseFile(PR_WVEFILE *self)
{
p_close(self->wvefile.fcb);
self->wvefile.fcb=NULL;
}
LOCAL_C VOID StoreFileName(PR_WVEFILE *self,TEXT *fname)
{
CloseFile(self);
f_fparse(fname,NULL,&self->wvefile.fname[0],&self->wvefile.crk);
hEnsurePath(&self->wvefile.fname[0]);
}
#pragma METHOD_CALL
METHOD INT wvefile_wve_new(PR_WVEFILE *self,TEXT *fname)
/*
Return the maximum duration in seconds consistent with the space on fspec
as a positive number. Otherwise return a negative error number.
*/
{
UINT minfree;
INT SSDType;
P_DINFO dinfo;
StoreFileName(self,fname);
p_dinfo(&self->wvefile.fname[0],&dinfo);
minfree=0x1000; /* need at least approx half a seconds worth of space */
SSDType=dinfo.mediatype&0xff;
if (SSDType==P_FMEDIA_FLASH)
return(E_FILE_VOLUME);
if (SSDType==P_FMEDIA_ROM || SSDType==P_FMEDIA_WRITEPROTECTED)
return(E_FILE_PROTECT);
if (dinfo.mediatype&P_FMEDIA_INTERNAL)
minfree+=0x2800; /* since the sound server takes 0x2800 bytes to run */
if (p_finfo(&self->wvefile.fname[0],&self->wvefile.info)>=0)
{
if (!(self->wvefile.info.status&P_FAWRITE))
return(E_FILE_RDONLY);
dinfo.free+=self->wvefile.info.size; /* credit length of existing file */
}
if (dinfo.free<minfree)
return(0);
return((UINT)(SamplesToTenths(dinfo.free-minfree)/10));
}
METHOD VOID wvefile_wve_open(PR_WVEFILE *self,TEXT *fname)
/*
If fname is NULL, attempt to open the stored file name.
Otherwise, attempt to open name.
*/
{
if (fname)
StoreFileName(self,fname);
self->wvefile.ret=p_finfo(&self->wvefile.fname[0],&self->wvefile.info);
if (self->wvefile.ret<0)
return;
CloseFile(self); /* file can be open after an error in playback */
self->wvefile.ret=p_open(&self->wvefile.fcb,&self->wvefile.fname[0],P_FSHARE);
if (self->wvefile.ret<0)
return;
self->wvefile.ret=p_read(self->wvefile.fcb,&self->wvefile.head,sizeof(SndFile));
if (self->wvefile.ret<0)
{
close:
CloseFile(self);
return;
}
if (p_scmp(&self->wvefile.head.Signature[0],ALawSignature))
{
self->wvefile.ret=E_FILE_INVALID;
goto close;
}
/* Wany "bootleg" files exist with incorrect Samples field */
/* The sound system services work off the file length and not Samples */
/* So we patch Samples here to the correct value */
self->wvefile.head.Samples=self->wvefile.info.size-sizeof(SndFile);
if (self->wvefile.head.Repeats==0)
self->wvefile.head.Repeats=1;
}
METHOD TEXT *wvefile_wve_sense_fname(PR_WVEFILE *self)
{
return(&self->wvefile.fname[0]);
}
METHOD VOID wvefile_wve_sense_info(PR_WVEFILE *self,WVEFILE_INFO *pi)
/*
Write all kinds of information to *pi.
*/
{
ULONG samples;
p_bfil(pi,sizeof(WVEFILE_INFO),0);
pi->device=&self->wvefile.fname[self->wvefile.crk.system];
pi->name=pi->device+self->wvefile.crk.device+self->wvefile.crk.path;
pi->nmlen=self->wvefile.crk.name;
if (self->wvefile.fcb==NULL)
return;
pi->duration=SamplesToTenths(self->wvefile.head.Samples);
pi->silence=(WORD)(((ULONG)self->wvefile.head.SilenceInTicks*5)>>4);
samples=EffectiveSamples(self->wvefile.head.Samples);
samples+=250*(ULONG)self->wvefile.head.SilenceInTicks; /* 250 samples per tick */
if (self->wvefile.head.Repeats>1 && self->wvefile.head.SilenceInTicks<2)
samples+=500; /* the minimum silence between repeats */
pi->repeats=self->wvefile.head.Repeats;
pi->total=SamplesToTenths(samples*pi->repeats);
pi->samples=self->wvefile.head.Samples;
pi->flen=self->wvefile.info.size;
}
METHOD VOID wvefile_wve_set_repeats(PR_WVEFILE *self,UINT repeats,UINT tenths)
/*
If repeats is zero or more, set the number of repeats and the trailing silence
to tenths in 1/10s of a second.
If repeats is zero, set the silence such that the total duration with the
current number of repeats is equal to tenths.
*/
{
INT ret;
INT silence,maxrepeats;
LONG total,period;
ret=0;
if (self->wvefile.fcb==NULL)
return;
if (repeats>0)
silence=(INT)(((ULONG)tenths<<4)/5); /* convert to ticks */
else
{ /* tenths is total desired time */
repeats=self->wvefile.head.Repeats;
total=tenths;
total*=800; /* convert tenths to samples */
period=EffectiveSamples(self->wvefile.head.Samples);
maxrepeats=(INT)(total/(period+500));
if (repeats<2 || repeats>maxrepeats)
repeats=maxrepeats;
if (repeats==0)
repeats=1;
silence=0;
if (repeats>1)
silence=(INT)((total-repeats*period+249*repeats)/(250*repeats));
}
if (silence==self->wvefile.head.SilenceInTicks && repeats==self->wvefile.head.Repeats)
return; /* no change */
self->wvefile.head.SilenceInTicks=silence;
self->wvefile.head.Repeats=repeats;
CloseFile(self);
ret=p_open(&self->wvefile.fcb,&self->wvefile.fname[0],P_FUPDATE);
if (ret>=0)
{
ret=p_write(self->wvefile.fcb,&self->wvefile.head,sizeof(SndFile));
CloseFile(self);
}
wvefile_wve_open(self,NULL);
f_leave(ret);
}