mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
301 lines
6.9 KiB
C++
301 lines
6.9 KiB
C++
/*
|
|
* Parallel port audio digitizer
|
|
*
|
|
* Toni Wilen 2010
|
|
*/
|
|
|
|
#include "sysconfig.h"
|
|
#include "sysdeps.h"
|
|
|
|
#include "options.h"
|
|
#include "events.h"
|
|
#include "custom.h"
|
|
#include "sampler.h"
|
|
|
|
#include "dxwrap.h"
|
|
|
|
#include <dsound.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include "win32.h"
|
|
|
|
#define SAMPLESIZE 4
|
|
|
|
static LPDIRECTSOUNDCAPTURE lpDS2r = NULL;
|
|
static LPDIRECTSOUNDCAPTUREBUFFER lpDSBprimary2r = NULL;
|
|
static LPDIRECTSOUNDCAPTUREBUFFER lpDSB2r = NULL;
|
|
static int inited;
|
|
static uae_u8 *samplebuffer;
|
|
static int sampleframes;
|
|
static int recordbufferframes;
|
|
static float clockspersample;
|
|
static int vsynccnt;
|
|
static int safediff;
|
|
float sampler_evtime;
|
|
|
|
static int capture_init (void)
|
|
{
|
|
HRESULT hr;
|
|
DSCBUFFERDESC sound_buffer_rec;
|
|
WAVEFORMATEX wavfmt;
|
|
TCHAR *name;
|
|
int samplerate = 44100;
|
|
|
|
if (currprefs.sampler_freq)
|
|
samplerate = currprefs.sampler_freq;
|
|
|
|
name = record_devices[currprefs.win32_samplersoundcard]->name;
|
|
|
|
wavfmt.wFormatTag = WAVE_FORMAT_PCM;
|
|
wavfmt.nChannels = 2;
|
|
wavfmt.nSamplesPerSec = samplerate;
|
|
wavfmt.wBitsPerSample = 16;
|
|
wavfmt.nBlockAlign = wavfmt.wBitsPerSample / 8 * wavfmt.nChannels;
|
|
wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * wavfmt.nSamplesPerSec;
|
|
wavfmt.cbSize = 0;
|
|
|
|
clockspersample = sampler_evtime / samplerate;
|
|
sampleframes = (samplerate + 49) / 50;
|
|
recordbufferframes = 16384;
|
|
if (currprefs.sampler_buffer)
|
|
recordbufferframes = currprefs.sampler_buffer;
|
|
|
|
hr = DirectSoundCaptureCreate (&record_devices[currprefs.win32_samplersoundcard]->guid, &lpDS2r, NULL);
|
|
if (FAILED (hr)) {
|
|
write_log (_T("SAMPLER: DirectSoundCaptureCreate('%s') failure: %s\n"), name, DXError (hr));
|
|
return 0;
|
|
}
|
|
memset (&sound_buffer_rec, 0, sizeof (DSCBUFFERDESC));
|
|
sound_buffer_rec.dwSize = sizeof (DSCBUFFERDESC);
|
|
sound_buffer_rec.dwBufferBytes = recordbufferframes * SAMPLESIZE;
|
|
sound_buffer_rec.lpwfxFormat = &wavfmt;
|
|
sound_buffer_rec.dwFlags = 0 ;
|
|
|
|
hr = lpDS2r->CreateCaptureBuffer (&sound_buffer_rec, &lpDSB2r, NULL);
|
|
if (FAILED (hr)) {
|
|
write_log (_T("SAMPLER: CreateCaptureSoundBuffer('%s') failure: %s\n"), name, DXError(hr));
|
|
return 0;
|
|
}
|
|
|
|
hr = lpDSB2r->Start (DSCBSTART_LOOPING);
|
|
if (FAILED (hr)) {
|
|
write_log (_T("SAMPLER: DirectSoundCaptureBuffer_Start('%s') failed: %s\n"), name, DXError (hr));
|
|
return 0;
|
|
}
|
|
samplebuffer = xcalloc (uae_u8, sampleframes * SAMPLESIZE);
|
|
write_log (_T("SAMPLER: Parallel port sampler initialized, CPS=%f, '%s'\n"), clockspersample, name);
|
|
return 1;
|
|
}
|
|
|
|
static void capture_free (void)
|
|
{
|
|
if (lpDSB2r) {
|
|
lpDSB2r->Stop ();
|
|
lpDSB2r->Release ();
|
|
write_log (_T("SAMPLER: Parallel port sampler freed\n"));
|
|
}
|
|
lpDSB2r = NULL;
|
|
if (lpDS2r)
|
|
lpDS2r->Release ();
|
|
lpDS2r = NULL;
|
|
xfree (samplebuffer);
|
|
samplebuffer = NULL;
|
|
}
|
|
|
|
static evt oldcycles;
|
|
static int oldoffset;
|
|
|
|
uae_u8 sampler_getsample (int channel)
|
|
{
|
|
#if 0
|
|
int cur_pos;
|
|
static int cap_pos;
|
|
static float diffsample;
|
|
#endif
|
|
static double doffset_offset;
|
|
HRESULT hr;
|
|
DWORD t;
|
|
void *p1, *p2;
|
|
DWORD len1, len2;
|
|
evt cycles;
|
|
int sample, samplecnt;
|
|
double doffset;
|
|
int offset;
|
|
|
|
if (!currprefs.sampler_stereo)
|
|
channel = 0;
|
|
|
|
if (!inited) {
|
|
DWORD pos;
|
|
if (!capture_init ()) {
|
|
capture_free ();
|
|
return 0;
|
|
}
|
|
inited = 1;
|
|
oldcycles = get_cycles ();
|
|
oldoffset = -1;
|
|
doffset_offset = 0;
|
|
hr = lpDSB2r->GetCurrentPosition (&t, &pos);
|
|
if (FAILED (hr)) {
|
|
sampler_free ();
|
|
return 0;
|
|
}
|
|
if (t >= pos)
|
|
safediff = t - pos;
|
|
else
|
|
safediff = recordbufferframes * SAMPLESIZE - pos + t;
|
|
write_log (_T("SAMPLER: safediff %d %d\n"), safediff, safediff + sampleframes * SAMPLESIZE);
|
|
safediff += 4 * sampleframes * SAMPLESIZE;
|
|
|
|
#if 0
|
|
diffsample = 0;
|
|
safepos = -recordbufferframes / 10 * SAMPLESIZE;
|
|
hr = lpDSB2r->GetCurrentPosition (&t, &pos);
|
|
cap_pos = pos;
|
|
cap_pos += safepos;
|
|
if (cap_pos < 0)
|
|
cap_pos += recordbufferframes * SAMPLESIZE;
|
|
if (cap_pos >= recordbufferframes * SAMPLESIZE)
|
|
cap_pos -= recordbufferframes * SAMPLESIZE;
|
|
if (FAILED (hr)) {
|
|
sampler_free ();
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
if (clockspersample < 1)
|
|
return 0;
|
|
uae_s16 *sbuf = (uae_s16*)samplebuffer;
|
|
|
|
vsynccnt = 0;
|
|
sample = 0;
|
|
samplecnt = 0;
|
|
cycles = (int)get_cycles () - (int)oldcycles;
|
|
doffset = doffset_offset + cycles / clockspersample;
|
|
offset = (int)doffset;
|
|
if (oldoffset < 0 || offset >= sampleframes || offset < 0) {
|
|
if (offset >= sampleframes) {
|
|
doffset -= offset;
|
|
doffset_offset = doffset;
|
|
}
|
|
if (oldoffset >= 0 && offset >= sampleframes) {
|
|
while (oldoffset < sampleframes) {
|
|
sample += sbuf[oldoffset * SAMPLESIZE / 2 + channel];
|
|
oldoffset++;
|
|
samplecnt++;
|
|
}
|
|
}
|
|
hr = lpDSB2r->GetCurrentPosition (&t, NULL);
|
|
int pos = t;
|
|
pos -= safediff;
|
|
if (pos < 0)
|
|
pos += recordbufferframes * SAMPLESIZE;
|
|
hr = lpDSB2r->Lock (pos, sampleframes * SAMPLESIZE, &p1, &len1, &p2, &len2, 0);
|
|
if (FAILED (hr)) {
|
|
write_log (_T("SAMPLER: Lock() failed %x\n"), hr);
|
|
return 0;
|
|
}
|
|
memcpy (samplebuffer, p1, len1);
|
|
if (p2)
|
|
memcpy (samplebuffer + len1, p2, len2);
|
|
lpDSB2r->Unlock (p1, len1, p2, len2);
|
|
|
|
#if 0
|
|
cap_pos = t;
|
|
cap_pos += sampleframes * SAMPLESIZE;
|
|
if (cap_pos < 0)
|
|
cap_pos += RECORDBUFFER * SAMPLESIZE;
|
|
if (cap_pos >= RECORDBUFFER * SAMPLESIZE)
|
|
cap_pos -= RECORDBUFFER * SAMPLESIZE;
|
|
|
|
hr = lpDSB2r->GetCurrentPosition (&t, &pos);
|
|
cur_pos = pos;
|
|
if (FAILED (hr))
|
|
return 0;
|
|
|
|
cur_pos += safepos;
|
|
if (cur_pos < 0)
|
|
cur_pos += RECORDBUFFER * SAMPLESIZE;
|
|
if (cur_pos >= RECORDBUFFER * SAMPLESIZE)
|
|
cur_pos -= RECORDBUFFER * SAMPLESIZE;
|
|
|
|
int diff;
|
|
if (cur_pos >= cap_pos)
|
|
diff = cur_pos - cap_pos;
|
|
else
|
|
diff = RECORDBUFFER * SAMPLESIZE - cap_pos + cur_pos;
|
|
if (diff > RECORDBUFFER * SAMPLESIZE / 2)
|
|
diff -= RECORDBUFFER * SAMPLESIZE;
|
|
diff /= SAMPLESIZE;
|
|
|
|
int diff2 = 100 * diff / (RECORDBUFFER / 2);
|
|
diffsample = -pow (diff2 < 0 ? -diff2 : diff2, 3.1);
|
|
if (diff2 < 0)
|
|
diffsample = -diffsample;
|
|
write_log (_T("%d\n"), diff);
|
|
|
|
write_log (_T("CAP=%05d CUR=%05d (%-05d) OFF=%05d %f\n"),
|
|
cap_pos / SAMPLESIZE, cur_pos / SAMPLESIZE, (cap_pos - cur_pos) / SAMPLESIZE, offset, doffset_offset);
|
|
#endif
|
|
|
|
if (offset < 0)
|
|
offset = 0;
|
|
if (offset >= sampleframes)
|
|
offset -= sampleframes;
|
|
|
|
oldoffset = 0;
|
|
oldcycles = get_cycles ();
|
|
}
|
|
|
|
while (oldoffset <= offset) {
|
|
sample += sbuf[oldoffset * SAMPLESIZE / 2 + channel];
|
|
samplecnt++;
|
|
oldoffset++;
|
|
}
|
|
oldoffset = offset;
|
|
|
|
if (samplecnt > 0)
|
|
sample /= samplecnt;
|
|
#if 1
|
|
/* yes, not 256, without this max recording volume would still be too quiet on my sound cards */
|
|
sample /= 128;
|
|
if (sample < -128)
|
|
sample = 0;
|
|
else if (sample > 127)
|
|
sample = 127;
|
|
return (uae_u8)(sample - 128);
|
|
#else
|
|
return (Uae_u8)((sample / 256) - 128);
|
|
#endif
|
|
}
|
|
|
|
int sampler_init (void)
|
|
{
|
|
if (currprefs.win32_samplersoundcard < 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
void sampler_free (void)
|
|
{
|
|
inited = 0;
|
|
vsynccnt = 0;
|
|
capture_free ();
|
|
}
|
|
|
|
void sampler_vsync (void)
|
|
{
|
|
if (!inited)
|
|
return;
|
|
|
|
vsynccnt++;
|
|
if (vsynccnt > 1) {
|
|
oldcycles = get_cycles ();
|
|
}
|
|
if (vsynccnt > 50) {
|
|
sampler_free ();
|
|
return;
|
|
}
|
|
}
|