mirror of
https://github.com/jamessanford/kegs.git
synced 2024-09-11 12:55:04 +00:00
2026 lines
43 KiB
C
2026 lines
43 KiB
C
/************************************************************************/
|
|
/* KEGS: Apple //gs Emulator */
|
|
/* Copyright 2002 by Kent Dickey */
|
|
/* */
|
|
/* This code is covered by the GNU GPL */
|
|
/* */
|
|
/* The KEGS web page is kegs.sourceforge.net */
|
|
/* You may contact the author at: kadickey@alumni.princeton.edu */
|
|
/************************************************************************/
|
|
|
|
const char rcsid_sound_c[] = "@(#)$KmKId: sound.c,v 1.108 2004-10-31 00:56:07-04 kentd Exp $";
|
|
|
|
#include "defc.h"
|
|
|
|
#define INCLUDE_RCSID_C
|
|
#include "sound.h"
|
|
#undef INCLUDE_RCSID_C
|
|
|
|
#if 0
|
|
# define DO_DOC_LOG
|
|
#endif
|
|
|
|
extern int Verbose;
|
|
extern int g_use_shmem;
|
|
extern word32 g_vbl_count;
|
|
extern int g_preferred_rate;
|
|
|
|
extern int g_c03ef_doc_ptr;
|
|
|
|
extern double g_last_vbl_dcycs;
|
|
|
|
void U_STACK_TRACE();
|
|
|
|
byte doc_ram[0x10000 + 16];
|
|
|
|
word32 doc_sound_ctl = 0;
|
|
word32 doc_saved_val = 0;
|
|
int g_doc_num_osc_en = 1;
|
|
double g_dcycs_per_doc_update = 1.0;
|
|
double g_dupd_per_dcyc = 1.0;
|
|
double g_drecip_osc_en_plus_2 = 1.0 / (double)(1 + 2);
|
|
|
|
int g_doc_saved_ctl = 0;
|
|
int g_queued_samps = 0;
|
|
int g_queued_nonsamps = 0;
|
|
int g_num_osc_interrupting = 0;
|
|
|
|
#if defined(HPUX) || defined(__linux__) || defined(_WIN32) || defined(MAC) || defined(__ANDROID__)
|
|
int g_audio_enable = -1;
|
|
#else
|
|
# if defined(OSS)
|
|
/* default to off for now */
|
|
int g_audio_enable = 0;
|
|
# else
|
|
/* Default to sound off */
|
|
int g_audio_enable = 0;
|
|
# endif
|
|
#endif
|
|
|
|
Doc_reg g_doc_regs[32];
|
|
|
|
word32 doc_reg_e0 = 0xff;
|
|
|
|
/* local function prototypes */
|
|
void doc_write_ctl_reg(int osc, int val, double dsamps);
|
|
|
|
|
|
int g_audio_rate = 0;
|
|
double g_daudio_rate = 0.0;
|
|
double g_drecip_audio_rate = 0.0;
|
|
double g_dsamps_per_dcyc = 0.0;
|
|
double g_dcycs_per_samp = 0.0;
|
|
float g_fsamps_per_dcyc = 0.0;
|
|
|
|
int g_doc_vol = 2;
|
|
|
|
#define MAX_C030_TIMES 18000
|
|
|
|
double g_last_sound_play_dsamp = 0.0;
|
|
|
|
float c030_fsamps[MAX_C030_TIMES + 1];
|
|
int g_num_c030_fsamps = 0;
|
|
|
|
#define DOC_SCAN_RATE (DCYCS_28_MHZ/32.0)
|
|
|
|
int g_pipe_fd[2] = { -1, -1 };
|
|
int g_pipe2_fd[2] = { -1, -1 };
|
|
word32 *g_sound_shm_addr = 0;
|
|
int g_sound_shm_pos = 0;
|
|
|
|
#define LEN_DOC_LOG 128
|
|
|
|
STRUCT(Doc_log) {
|
|
char *msg;
|
|
int osc;
|
|
double dsamps;
|
|
double dtmp2;
|
|
int etc;
|
|
Doc_reg doc_reg;
|
|
};
|
|
|
|
Doc_log g_doc_log[LEN_DOC_LOG];
|
|
int g_doc_log_pos = 0;
|
|
|
|
|
|
#ifdef DO_DOC_LOG
|
|
# define DOC_LOG(a,b,c,d) doc_log_rout(a,b,c,d)
|
|
#else
|
|
# define DOC_LOG(a,b,c,d)
|
|
#endif
|
|
|
|
#define UPDATE_G_DCYCS_PER_DOC_UPDATE(osc_en) \
|
|
g_dcycs_per_doc_update = (double)((osc_en + 2) * DCYCS_1_MHZ) / \
|
|
DOC_SCAN_RATE; \
|
|
g_dupd_per_dcyc = 1.0 / g_dcycs_per_doc_update; \
|
|
g_drecip_osc_en_plus_2 = 1.0 / (double)(osc_en + 2);
|
|
|
|
#define SND_PTR_SHIFT 14
|
|
#define SND_PTR_SHIFT_DBL ((double)(1 << SND_PTR_SHIFT))
|
|
|
|
void
|
|
doc_log_rout(char *msg, int osc, double dsamps, int etc)
|
|
{
|
|
int pos;
|
|
|
|
pos = g_doc_log_pos;
|
|
g_doc_log[pos].msg = msg;
|
|
g_doc_log[pos].osc = osc;
|
|
g_doc_log[pos].dsamps = dsamps;
|
|
g_doc_log[pos].dtmp2 = g_last_sound_play_dsamp;
|
|
g_doc_log[pos].etc = etc;
|
|
if(osc >= 0 && osc < 32) {
|
|
g_doc_log[pos].doc_reg = g_doc_regs[osc];
|
|
}
|
|
pos++;
|
|
if(pos >= LEN_DOC_LOG) {
|
|
pos = 0;
|
|
}
|
|
|
|
doc_printf("log: %s, osc:%d dsamp:%f, etc:%d\n", msg, osc, dsamps, etc);
|
|
|
|
g_doc_log_pos = pos;
|
|
}
|
|
|
|
extern double g_cur_dcycs;
|
|
|
|
void
|
|
show_doc_log(void)
|
|
{
|
|
FILE *docfile;
|
|
Doc_reg *rptr;
|
|
double dsamp_start;
|
|
int osc, ctl, freq;
|
|
int pos;
|
|
int i;
|
|
|
|
docfile = fopen("doc_log_out", "w");
|
|
if(docfile == 0) {
|
|
printf("fopen failed, errno: %d\n", errno);
|
|
return;
|
|
}
|
|
pos = g_doc_log_pos;
|
|
fprintf(docfile, "DOC log pos: %d\n", pos);
|
|
dsamp_start = g_doc_log[pos].dsamps;
|
|
for(i = 0; i < LEN_DOC_LOG; i++) {
|
|
rptr = &(g_doc_log[pos].doc_reg);
|
|
osc = g_doc_log[pos].osc;
|
|
ctl = rptr->ctl;
|
|
freq = rptr->freq;
|
|
if(osc < 0) {
|
|
ctl = 0;
|
|
freq = 0;
|
|
}
|
|
fprintf(docfile, "%03x:%03x: %-11s ds:%11.1f dt2:%10.1f "
|
|
"etc:%08x o:%02x c:%02x fq:%04x\n",
|
|
i, pos, g_doc_log[pos].msg,
|
|
g_doc_log[pos].dsamps - dsamp_start,
|
|
g_doc_log[pos].dtmp2,
|
|
g_doc_log[pos].etc, osc & 0xff, ctl, freq);
|
|
if(osc >= 0) {
|
|
fprintf(docfile, " ire:%d,%d,%d ptr4:%08x "
|
|
"inc4:%08x comp_ds:%.1f left:%04x, vol:%02x "
|
|
"wptr:%02x, wsz:%02x, 4st:%08x, 4end:%08x\n",
|
|
rptr->has_irq_pending, rptr->running,
|
|
rptr->event, 4*rptr->cur_acc, 4*rptr->cur_inc,
|
|
rptr->complete_dsamp - dsamp_start,
|
|
rptr->samps_left, rptr->vol, rptr->waveptr,
|
|
rptr->wavesize, 4*rptr->cur_start,
|
|
4*rptr->cur_end);
|
|
}
|
|
pos++;
|
|
if(pos >= LEN_DOC_LOG) {
|
|
pos = 0;
|
|
}
|
|
}
|
|
|
|
fprintf(docfile, "cur_dcycs: %f\n", g_cur_dcycs);
|
|
fprintf(docfile, "dsamps_now: %f\n",
|
|
(g_cur_dcycs * g_dsamps_per_dcyc) - dsamp_start);
|
|
fprintf(docfile, "g_doc_num_osc_en: %d\n", g_doc_num_osc_en);
|
|
fclose(docfile);
|
|
}
|
|
|
|
void
|
|
sound_init()
|
|
{
|
|
Doc_reg *rptr;
|
|
int i;
|
|
|
|
for(i = 0; i < 32; i++) {
|
|
rptr = &(g_doc_regs[i]);
|
|
rptr->dsamp_ev = 0.0;
|
|
rptr->dsamp_ev2 = 0.0;
|
|
rptr->complete_dsamp = 0.0;
|
|
rptr->samps_left = 0;
|
|
rptr->cur_acc = 0;
|
|
rptr->cur_inc = 0;
|
|
rptr->cur_start = 0;
|
|
rptr->cur_end = 0;
|
|
rptr->cur_mask = 0;
|
|
rptr->size_bytes = 0;
|
|
rptr->event = 0;
|
|
rptr->running = 0;
|
|
rptr->has_irq_pending = 0;
|
|
rptr->freq = 0;
|
|
rptr->vol = 0;
|
|
rptr->waveptr = 0;
|
|
rptr->ctl = 1;
|
|
rptr->wavesize = 0;
|
|
rptr->last_samp_val = 0;
|
|
}
|
|
|
|
sound_init_general();
|
|
}
|
|
|
|
|
|
void
|
|
sound_init_general()
|
|
{
|
|
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__ANDROID__)
|
|
int pid;
|
|
int shmid;
|
|
int tmp;
|
|
int i;
|
|
#endif
|
|
word32 *shmaddr;
|
|
int size;
|
|
int ret;
|
|
|
|
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__ANDROID__)
|
|
if(!g_use_shmem) {
|
|
if(g_audio_enable < 0) {
|
|
printf("Defaulting audio off for slow X display\n");
|
|
g_audio_enable = 0;
|
|
}
|
|
}
|
|
#endif
|
|
ret = 0;
|
|
|
|
if(g_audio_enable == 0) {
|
|
set_audio_rate(g_preferred_rate);
|
|
return;
|
|
}
|
|
|
|
size = SOUND_SHM_SAMP_SIZE * SAMPLE_CHAN_SIZE;
|
|
|
|
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__ANDROID__)
|
|
shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
|
|
if(shmid < 0) {
|
|
printf("sound_init: shmget ret: %d, errno: %d\n", shmid,
|
|
errno);
|
|
exit(2);
|
|
}
|
|
|
|
shmaddr = shmat(shmid, 0, 0);
|
|
tmp = (int)PTR2WORD(shmaddr);
|
|
if(tmp == -1) {
|
|
printf("sound_init: shmat ret: %p, errno: %d\n", shmaddr,
|
|
errno);
|
|
exit(3);
|
|
}
|
|
|
|
ret = shmctl(shmid, IPC_RMID, 0);
|
|
if(ret < 0) {
|
|
printf("sound_init: shmctl ret: %d, errno: %d\n", ret, errno);
|
|
exit(4);
|
|
}
|
|
#else
|
|
/* windows and mac */
|
|
shmaddr = malloc(size);
|
|
memset(shmaddr, 0, size);
|
|
#endif
|
|
|
|
g_sound_shm_addr = shmaddr;
|
|
|
|
fflush(stdout);
|
|
|
|
#if !defined(MAC) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__ANDROID__)
|
|
/* prepare pipe so parent can signal child each other */
|
|
/* pipe[0] = read side, pipe[1] = write end */
|
|
ret = pipe(&g_pipe_fd[0]);
|
|
if(ret < 0) {
|
|
printf("sound_init: pipe ret: %d, errno: %d\n", ret, errno);
|
|
exit(5);
|
|
}
|
|
ret = pipe(&g_pipe2_fd[0]);
|
|
if(ret < 0) {
|
|
printf("sound_init: pipe ret: %d, errno: %d\n", ret, errno);
|
|
exit(5);
|
|
}
|
|
|
|
|
|
printf("pipes: pipe_fd = %d, %d pipe2_fd: %d,%d\n",
|
|
g_pipe_fd[0], g_pipe_fd[1], g_pipe2_fd[0], g_pipe2_fd[1]);
|
|
fflush(stdout);
|
|
|
|
pid = fork();
|
|
switch(pid) {
|
|
case 0:
|
|
/* child */
|
|
/* close stdin and write-side of pipe */
|
|
close(0);
|
|
/* Close other fds to make sure X window fd is closed */
|
|
for(i = 3; i < 100; i++) {
|
|
if((i != g_pipe_fd[0]) && (i != g_pipe2_fd[1])) {
|
|
close(i);
|
|
}
|
|
}
|
|
close(g_pipe_fd[1]); /*make sure write pipe closed*/
|
|
close(g_pipe2_fd[0]); /*make sure read pipe closed*/
|
|
child_sound_loop(g_pipe_fd[0], g_pipe2_fd[1], g_sound_shm_addr);
|
|
printf("Child sound loop returned\n");
|
|
exit(0);
|
|
case -1:
|
|
/* error */
|
|
printf("sound_init: fork ret: -1, errno: %d\n", errno);
|
|
exit(6);
|
|
default:
|
|
/* parent */
|
|
/* close read-side of pipe1, and the write side of pipe2 */
|
|
close(g_pipe_fd[0]);
|
|
close(g_pipe2_fd[1]);
|
|
doc_printf("Child is pid: %d\n", pid);
|
|
}
|
|
|
|
parent_sound_get_sample_rate(g_pipe2_fd[0]);
|
|
#endif
|
|
#ifdef MAC
|
|
macsnd_init(shmaddr);
|
|
#endif
|
|
#ifdef __ANDROID__
|
|
android_snd_init(shmaddr);
|
|
#endif
|
|
#ifdef _WIN32
|
|
win32snd_init(shmaddr);
|
|
#endif
|
|
|
|
}
|
|
|
|
void
|
|
parent_sound_get_sample_rate(int read_fd)
|
|
{
|
|
word32 tmp;
|
|
int ret;
|
|
|
|
ret = read(read_fd, &tmp, 4);
|
|
if(ret != 4) {
|
|
printf("parent dying, could not get sample rate from child\n");
|
|
printf("ret: %d, fd: %d errno:%d\n", ret, read_fd, errno);
|
|
exit(1);
|
|
}
|
|
close(read_fd);
|
|
|
|
set_audio_rate(tmp);
|
|
}
|
|
|
|
void
|
|
set_audio_rate(int rate)
|
|
{
|
|
g_audio_rate = rate;
|
|
g_daudio_rate = (rate)*1.0;
|
|
g_drecip_audio_rate = 1.0/(rate);
|
|
g_dsamps_per_dcyc = ((rate*1.0) / DCYCS_1_MHZ);
|
|
g_dcycs_per_samp = (DCYCS_1_MHZ / (rate*1.0));
|
|
g_fsamps_per_dcyc = (float)((rate*1.0) / DCYCS_1_MHZ);
|
|
}
|
|
|
|
void
|
|
sound_reset(double dcycs)
|
|
{
|
|
double dsamps;
|
|
int i;
|
|
|
|
dsamps = dcycs * g_dsamps_per_dcyc;
|
|
for(i = 0; i < 32; i++) {
|
|
doc_write_ctl_reg(i, g_doc_regs[i].ctl | 1, dsamps);
|
|
doc_reg_e0 = 0xff;
|
|
if(g_doc_regs[i].has_irq_pending) {
|
|
halt_printf("reset: has_irq[%02x] = %d\n", i,
|
|
g_doc_regs[i].has_irq_pending);
|
|
}
|
|
g_doc_regs[i].has_irq_pending = 0;
|
|
}
|
|
if(g_num_osc_interrupting) {
|
|
halt_printf("reset: num_osc_int:%d\n", g_num_osc_interrupting);
|
|
}
|
|
g_num_osc_interrupting = 0;
|
|
|
|
g_doc_num_osc_en = 1;
|
|
UPDATE_G_DCYCS_PER_DOC_UPDATE(1);
|
|
}
|
|
|
|
void
|
|
sound_shutdown()
|
|
{
|
|
#ifdef _WIN32
|
|
win32snd_shutdown();
|
|
#else
|
|
if((g_audio_enable != 0) && g_pipe_fd[1] != 0) {
|
|
close(g_pipe_fd[1]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void
|
|
sound_update(double dcycs)
|
|
{
|
|
double dsamps;
|
|
/* Called every VBL time to update sound status */
|
|
|
|
/* "play" sounds for this vbl */
|
|
|
|
dsamps = dcycs * g_dsamps_per_dcyc;
|
|
DOC_LOG("do_snd_pl", -1, dsamps, 0);
|
|
sound_play(dsamps);
|
|
}
|
|
|
|
#define MAX_SND_BUF 65536
|
|
|
|
int g_samp_buf[2*MAX_SND_BUF];
|
|
word32 zero_buf[SOUND_SHM_SAMP_SIZE];
|
|
|
|
double g_doc_dsamps_extra = 0.0;
|
|
|
|
float g_fvoices = 0.0;
|
|
|
|
word32 g_cycs_in_sound1 = 0;
|
|
word32 g_cycs_in_sound2 = 0;
|
|
word32 g_cycs_in_sound3 = 0;
|
|
word32 g_cycs_in_sound4 = 0;
|
|
word32 g_cycs_in_start_sound = 0;
|
|
word32 g_cycs_in_est_sound = 0;
|
|
|
|
int g_num_snd_plays = 0;
|
|
int g_num_doc_events = 0;
|
|
int g_num_start_sounds = 0;
|
|
int g_num_scan_osc = 0;
|
|
int g_num_recalc_snd_parms = 0;
|
|
|
|
word32 g_last_c030_vbl_count = 0;
|
|
int g_c030_state = 0;
|
|
|
|
#define VAL_C030_RANGE (32768)
|
|
#define VAL_C030_BASE (-16384)
|
|
|
|
int g_sound_file_num = 0;
|
|
int g_sound_file_fd = -1;
|
|
int g_send_sound_to_file = 0;
|
|
int g_send_file_bytes = 0;
|
|
|
|
void
|
|
open_sound_file()
|
|
{
|
|
char name[256];
|
|
int fd;
|
|
|
|
sprintf(name, "snd.out.%d", g_sound_file_num);
|
|
|
|
fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0x1ff);
|
|
if(fd < 0) {
|
|
printf("open_sound_file open ret: %d, errno: %d\n", fd, errno);
|
|
exit(1);
|
|
}
|
|
|
|
g_sound_file_fd = fd;
|
|
g_sound_file_num++;
|
|
g_send_file_bytes = 0;
|
|
}
|
|
|
|
void
|
|
close_sound_file()
|
|
{
|
|
if(g_sound_file_fd >= 0) {
|
|
close(g_sound_file_fd);
|
|
}
|
|
|
|
g_sound_file_fd = -1;
|
|
}
|
|
|
|
void
|
|
check_for_range(word32 *addr, int num_samps, int offset)
|
|
{
|
|
short *shortptr;
|
|
int i;
|
|
int left;
|
|
int right;
|
|
int max;
|
|
|
|
max = -32768;
|
|
|
|
if(num_samps > SOUND_SHM_SAMP_SIZE) {
|
|
halt_printf("num_samps: %d > %d!\n", num_samps,
|
|
SOUND_SHM_SAMP_SIZE);
|
|
}
|
|
|
|
for(i = 0; i < num_samps; i++) {
|
|
shortptr = (short *)&(addr[i]);
|
|
left = shortptr[0];
|
|
right = shortptr[1];
|
|
if((left > 0x3000) || (right > 0x3000)) {
|
|
halt_printf("Sample %d of %d at snd_buf: %p is: "
|
|
"%d/%d\n", i + offset, num_samps,
|
|
&addr[i], left, right);
|
|
return;
|
|
}
|
|
|
|
max = MAX(max, left);
|
|
max = MAX(max, right);
|
|
}
|
|
|
|
printf("check4 max: %d over %d\n", max, num_samps);
|
|
}
|
|
|
|
void
|
|
send_sound_to_file(word32 *addr, int shm_pos, int num_samps)
|
|
{
|
|
int size;
|
|
int ret;
|
|
|
|
if(g_sound_file_fd < 0) {
|
|
open_sound_file();
|
|
}
|
|
|
|
size = 0;
|
|
if((num_samps + shm_pos) > SOUND_SHM_SAMP_SIZE) {
|
|
size = SOUND_SHM_SAMP_SIZE - shm_pos;
|
|
g_send_file_bytes += (size * 4);
|
|
|
|
ret = write(g_sound_file_fd, &(addr[shm_pos]), 4*size);
|
|
if(ret != 4*size) {
|
|
halt_printf("wrote %d not %d\n", ret, 4*size);
|
|
}
|
|
|
|
if(g_doc_vol < 3) {
|
|
check_for_range(&(addr[shm_pos]), size, 0);
|
|
} else {
|
|
printf("Not checking %d bytes since vol: %d\n",
|
|
4*size, g_doc_vol);
|
|
}
|
|
shm_pos = 0;
|
|
num_samps -= size;
|
|
}
|
|
|
|
g_send_file_bytes += (num_samps * 4);
|
|
|
|
ret = write(g_sound_file_fd, &(addr[shm_pos]), 4*num_samps);
|
|
if(ret != 4*num_samps) {
|
|
halt_printf("wrote %d not %d\n", ret, 4*num_samps);
|
|
}
|
|
|
|
if(g_doc_vol < 3) {
|
|
check_for_range(&(addr[shm_pos]), num_samps, size);
|
|
} else {
|
|
printf("Not checking2 %d bytes since vol: %d\n",
|
|
4*num_samps, g_doc_vol);
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
send_sound(int real_samps, int size)
|
|
{
|
|
word32 tmp;
|
|
int ret;
|
|
|
|
if(g_audio_enable == 0) {
|
|
printf("Entered send_sound but audio off!\n");
|
|
exit(2);
|
|
}
|
|
|
|
if(real_samps) {
|
|
tmp = size + 0xa2000000;
|
|
} else {
|
|
tmp = size + 0xa1000000;
|
|
}
|
|
DOC_LOG("send_sound", -1, g_last_sound_play_dsamp,
|
|
(real_samps << 30) + size);
|
|
|
|
#if defined(MAC) || defined(_WIN32) || defined(__ANDROID__)
|
|
ret = 0;
|
|
child_sound_playit(tmp);
|
|
#else
|
|
/* Although this looks like a big/little-endian issue, since the */
|
|
/* child is also reading an int, it just works with no byte swap */
|
|
ret = write(g_pipe_fd[1], &tmp, 4);
|
|
if(ret != 4) {
|
|
halt_printf("send_sound, wr ret: %d, errno: %d\n", ret, errno);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
show_c030_state()
|
|
{
|
|
show_c030_samps(&(g_samp_buf[0]), 100);
|
|
}
|
|
|
|
void
|
|
show_c030_samps(int *outptr, int num)
|
|
{
|
|
int i;
|
|
|
|
printf("c030_fsamps[]: %d\n", g_num_c030_fsamps);
|
|
|
|
for(i = 0; i < g_num_c030_fsamps+2; i++) {
|
|
printf("%3d: %5.3f\n", i, c030_fsamps[i]);
|
|
}
|
|
|
|
printf("Samples[] = %d\n", num);
|
|
|
|
for(i = 0; i < num+2; i++) {
|
|
printf("%4d: %d %d\n", i, outptr[0], outptr[1]);
|
|
outptr += 2;
|
|
}
|
|
}
|
|
|
|
int g_sound_play_depth = 0;
|
|
|
|
void
|
|
sound_play(double dsamps)
|
|
{
|
|
register word32 start_time1, start_time2, start_time3, start_time4;
|
|
register word32 end_time1, end_time2, end_time3;
|
|
Doc_reg *rptr;
|
|
int *outptr;
|
|
int *outptr_start;
|
|
word32 *sndptr;
|
|
double complete_dsamp;
|
|
double cur_dsamp;
|
|
double last_dsamp;
|
|
double dsamp_now;
|
|
double dnum_samps;
|
|
int val, val2;
|
|
int new_val;
|
|
float ftmp;
|
|
int imul;
|
|
int off;
|
|
int num;
|
|
float fsampnum;
|
|
float next_fsampnum;
|
|
int c030_lo_val, c030_hi_val;
|
|
float fc030_range;
|
|
float fc030_base;
|
|
int sampnum;
|
|
int next_sampnum;
|
|
float fpercent;
|
|
int c030_state;
|
|
int val0, val1;
|
|
word32 cur_acc;
|
|
word32 cur_pos;
|
|
word32 cur_mask;
|
|
word32 cur_inc;
|
|
word32 cur_end;
|
|
int ctl;
|
|
int num_osc_en;
|
|
int samps_left;
|
|
int samps_to_do;
|
|
int samps_played;
|
|
int samp_offset;
|
|
int snd_buf_init;
|
|
int pos;
|
|
int num_running;
|
|
int num_samps;
|
|
int osc;
|
|
int done;
|
|
int i, j;
|
|
|
|
|
|
GET_ITIMER(start_time1);
|
|
|
|
g_num_snd_plays++;
|
|
if(g_sound_play_depth) {
|
|
halt_printf("Nested sound_play!\n");
|
|
}
|
|
|
|
g_sound_play_depth++;
|
|
|
|
/* calc sample num */
|
|
|
|
last_dsamp = g_last_sound_play_dsamp;
|
|
num_samps = (int)(dsamps - g_last_sound_play_dsamp);
|
|
dnum_samps = (double)num_samps;
|
|
|
|
dsamp_now = last_dsamp + dnum_samps;
|
|
|
|
if(num_samps < 1) {
|
|
/* just say no */
|
|
g_sound_play_depth--;
|
|
return;
|
|
}
|
|
|
|
DOC_LOG("sound_play", -1, dsamp_now, num_samps);
|
|
|
|
if(num_samps > MAX_SND_BUF) {
|
|
printf("num_samps: %d, too big!\n", num_samps);
|
|
g_sound_play_depth--;
|
|
return;
|
|
}
|
|
|
|
|
|
GET_ITIMER(start_time4);
|
|
|
|
outptr_start = &(g_samp_buf[0]);
|
|
outptr = outptr_start;
|
|
|
|
snd_buf_init = 0;
|
|
|
|
samps_played = 0;
|
|
|
|
num = g_num_c030_fsamps;
|
|
|
|
if(num || ((g_vbl_count - g_last_c030_vbl_count) < 240)) {
|
|
|
|
if(num) {
|
|
g_last_c030_vbl_count = g_vbl_count;
|
|
}
|
|
|
|
pos = 0;
|
|
outptr = outptr_start;
|
|
c030_state = g_c030_state;
|
|
|
|
c030_hi_val = ((VAL_C030_BASE + VAL_C030_RANGE)*g_doc_vol) >> 4;
|
|
c030_lo_val = (VAL_C030_BASE * g_doc_vol) >> 4;
|
|
|
|
fc030_range = (float)(((VAL_C030_RANGE) * g_doc_vol) >> 4);
|
|
fc030_base = (float)(((VAL_C030_BASE) * g_doc_vol) >> 4);
|
|
|
|
val = c030_lo_val;
|
|
if(c030_state) {
|
|
val = c030_hi_val;
|
|
}
|
|
|
|
snd_buf_init++;
|
|
|
|
c030_fsamps[num] = (float)(num_samps);
|
|
c030_fsamps[num+1] = (float)(num_samps+1);
|
|
|
|
ftmp = (float)num_samps;
|
|
/* ensure that all samps are in range */
|
|
for(i = num - 1; i >= 0; i--) {
|
|
if(c030_fsamps[i] > ftmp) {
|
|
c030_fsamps[i] = ftmp;
|
|
}
|
|
}
|
|
|
|
num++;
|
|
fsampnum = c030_fsamps[0];
|
|
sampnum = (int)fsampnum;
|
|
fpercent = (float)0.0;
|
|
i = 0;
|
|
|
|
while(i < num) {
|
|
next_fsampnum = c030_fsamps[i+1];
|
|
next_sampnum = (int)next_fsampnum;
|
|
if(sampnum < 0 || sampnum > num_samps) {
|
|
halt_printf("play c030: [%d]:%f is %d, > %d\n",
|
|
i, fsampnum, sampnum, num_samps);
|
|
break;
|
|
}
|
|
|
|
/* write in samples to all samps < me */
|
|
new_val = c030_lo_val;
|
|
if(c030_state) {
|
|
new_val = c030_hi_val;
|
|
}
|
|
for(j = pos; j < sampnum; j++) {
|
|
outptr[0] = new_val;
|
|
outptr[1] = new_val;
|
|
outptr += 2;
|
|
pos++;
|
|
}
|
|
|
|
/* now, calculate me */
|
|
fpercent = (float)0.0;
|
|
if(c030_state) {
|
|
fpercent = (fsampnum - (float)sampnum);
|
|
}
|
|
|
|
c030_state = !c030_state;
|
|
|
|
while(next_sampnum == sampnum) {
|
|
if(c030_state) {
|
|
fpercent += (next_fsampnum - fsampnum);
|
|
}
|
|
i++;
|
|
fsampnum = next_fsampnum;
|
|
|
|
next_fsampnum = c030_fsamps[i+1];
|
|
next_sampnum = (int)next_fsampnum;
|
|
c030_state = !c030_state;
|
|
}
|
|
|
|
if(c030_state) {
|
|
/* add in fractional time */
|
|
ftmp = (int)(fsampnum + (float)1.0);
|
|
fpercent += (ftmp - fsampnum);
|
|
}
|
|
|
|
if((fpercent < (float)0.0) || (fpercent > (float)1.0)) {
|
|
halt_printf("fpercent: %d = %f\n", i, fpercent);
|
|
show_c030_samps(outptr_start, num_samps);
|
|
break;
|
|
}
|
|
|
|
val = (int)((fpercent * fc030_range) + fc030_base);
|
|
outptr[0] = val;
|
|
outptr[1] = val;
|
|
outptr += 2;
|
|
pos++;
|
|
i++;
|
|
|
|
sampnum = next_sampnum;
|
|
fsampnum = next_fsampnum;
|
|
}
|
|
|
|
samps_played += num_samps;
|
|
|
|
/* since we pretended to get one extra sample, we will */
|
|
/* have toggled the speaker one time too many. Fix it */
|
|
g_c030_state = !c030_state;
|
|
|
|
if(g_send_sound_to_file) {
|
|
show_c030_samps(outptr_start, num_samps);
|
|
}
|
|
}
|
|
|
|
g_num_c030_fsamps = 0;
|
|
|
|
GET_ITIMER(start_time2);
|
|
|
|
num_running = 0;
|
|
|
|
num_osc_en = g_doc_num_osc_en;
|
|
|
|
done = 0;
|
|
while(!done) {
|
|
done = 1;
|
|
for(j = 0; j < num_osc_en; j++) {
|
|
osc = j;
|
|
rptr = &(g_doc_regs[osc]);
|
|
complete_dsamp = rptr->complete_dsamp;
|
|
samps_left = rptr->samps_left;
|
|
cur_acc = rptr->cur_acc;
|
|
cur_mask = rptr->cur_mask;
|
|
cur_inc = rptr->cur_inc;
|
|
cur_end = rptr->cur_end;
|
|
if(!rptr->running || cur_inc == 0 ||
|
|
(complete_dsamp >= dsamp_now)) {
|
|
continue;
|
|
}
|
|
|
|
done = 0;
|
|
ctl = rptr->ctl;
|
|
|
|
samp_offset = 0;
|
|
if(complete_dsamp > last_dsamp) {
|
|
samp_offset = (int)(complete_dsamp- last_dsamp);
|
|
if(samp_offset > num_samps) {
|
|
rptr->complete_dsamp = dsamp_now;
|
|
continue;
|
|
}
|
|
}
|
|
outptr = outptr_start + 2 * samp_offset;
|
|
if(ctl & 0x10) {
|
|
/* other channel */
|
|
outptr += 1;
|
|
}
|
|
|
|
imul = (rptr->vol * g_doc_vol);
|
|
off = imul * 128;
|
|
|
|
samps_to_do = MIN(samps_left, num_samps - samp_offset);
|
|
if(imul == 0 || samps_to_do == 0) {
|
|
/* produce no sound */
|
|
samps_left = samps_left - samps_to_do;
|
|
cur_acc += cur_inc * samps_to_do;
|
|
rptr->samps_left = samps_left;
|
|
rptr->cur_acc = cur_acc;
|
|
cur_dsamp = last_dsamp +
|
|
(double)(samps_to_do + samp_offset);
|
|
DOC_LOG("nosnd", osc, cur_dsamp, samps_to_do);
|
|
rptr->complete_dsamp = dsamp_now;
|
|
cur_pos = rptr->cur_start+(cur_acc & cur_mask);
|
|
if(samps_left <= 0) {
|
|
doc_sound_end(osc, 1, cur_dsamp,
|
|
dsamp_now);
|
|
val = 0;
|
|
j--;
|
|
} else {
|
|
val = doc_ram[cur_pos >> SND_PTR_SHIFT];
|
|
}
|
|
rptr->last_samp_val = val;
|
|
continue;
|
|
}
|
|
|
|
if(snd_buf_init == 0) {
|
|
memset(outptr_start, 0,
|
|
2*sizeof(outptr_start[0])*num_samps);
|
|
snd_buf_init++;
|
|
}
|
|
|
|
val = 0;
|
|
rptr->complete_dsamp = dsamp_now;
|
|
cur_pos = rptr->cur_start + (cur_acc & cur_mask);
|
|
for(i = 0; i < samps_to_do; i++) {
|
|
pos = cur_pos >> SND_PTR_SHIFT;
|
|
cur_pos += cur_inc;
|
|
cur_acc += cur_inc;
|
|
val = doc_ram[pos];
|
|
|
|
val2 = (val * imul - off) >> 4;
|
|
if((val == 0) || (cur_pos >= cur_end)) {
|
|
cur_dsamp = last_dsamp +
|
|
(double)(samp_offset + i + 1);
|
|
rptr->cur_acc = cur_acc;
|
|
rptr->samps_left = 0;
|
|
DOC_LOG("end or 0", osc, cur_dsamp,
|
|
(pos << 16) + ((i &0xff) << 8) +
|
|
val);
|
|
doc_sound_end(osc, val, cur_dsamp,
|
|
dsamp_now);
|
|
val = 0;
|
|
break;
|
|
}
|
|
|
|
val2 = outptr[0] + val2;
|
|
|
|
samps_left--;
|
|
*outptr = val2;
|
|
outptr += 2;
|
|
}
|
|
|
|
rptr->last_samp_val = val;
|
|
|
|
if(val != 0) {
|
|
rptr->cur_acc = cur_acc;
|
|
rptr->samps_left = samps_left;
|
|
rptr->complete_dsamp = dsamp_now;
|
|
}
|
|
|
|
samps_played += samps_to_do;
|
|
DOC_LOG("splayed", osc, dsamp_now,
|
|
(samps_to_do << 16) + (pos & 0xffff));
|
|
}
|
|
}
|
|
|
|
GET_ITIMER(end_time2);
|
|
|
|
g_cycs_in_sound2 += (end_time2 - start_time2);
|
|
|
|
g_last_sound_play_dsamp = dsamp_now;
|
|
|
|
GET_ITIMER(start_time3);
|
|
|
|
outptr = outptr_start;
|
|
|
|
pos = g_sound_shm_pos;
|
|
sndptr = g_sound_shm_addr;
|
|
|
|
#if 0
|
|
printf("samps_left: %d, num_samps: %d\n", samps_left, num_samps);
|
|
#endif
|
|
|
|
if(g_audio_enable != 0) {
|
|
|
|
if(snd_buf_init) {
|
|
/* convert sound buf */
|
|
|
|
for(i = 0; i < num_samps; i++) {
|
|
val0 = outptr[0];
|
|
val1 = outptr[1];
|
|
val = val0;
|
|
if(val0 > 32767) {
|
|
val = 32767;
|
|
}
|
|
if(val0 < -32768) {
|
|
val = -32768;
|
|
}
|
|
|
|
val0 = val;
|
|
val = val1;
|
|
if(val1 > 32767) {
|
|
val = 32767;
|
|
}
|
|
if(val1 < -32768) {
|
|
val = -32768;
|
|
}
|
|
|
|
|
|
outptr += 2;
|
|
|
|
#if defined(__linux__) || defined(OSS)
|
|
/* Linux seems to expect little-endian */
|
|
/* samples always, even on PowerPC */
|
|
# ifdef KEGS_LITTLE_ENDIAN
|
|
sndptr[pos] = (val << 16) + (val0 & 0xffff);
|
|
# else
|
|
sndptr[pos] = ((val & 0xff) << 24) +
|
|
((val & 0xff00) << 8) +
|
|
((val0 & 0xff) << 8) +
|
|
((val0 >> 8) & 0xff);
|
|
# endif
|
|
#else
|
|
# ifdef KEGS_LITTLE_ENDIAN
|
|
sndptr[pos] = (val << 16) + (val0 & 0xffff);
|
|
# else
|
|
sndptr[pos] = (val0 << 16) + (val & 0xffff);
|
|
# endif
|
|
#endif
|
|
pos++;
|
|
if(pos >= SOUND_SHM_SAMP_SIZE) {
|
|
pos = 0;
|
|
}
|
|
}
|
|
|
|
if(g_queued_nonsamps) {
|
|
/* force out old 0 samps */
|
|
send_sound(0, g_queued_nonsamps);
|
|
g_queued_nonsamps = 0;
|
|
}
|
|
|
|
if(g_send_sound_to_file) {
|
|
send_sound_to_file(g_sound_shm_addr,
|
|
g_sound_shm_pos, num_samps);
|
|
}
|
|
|
|
g_queued_samps += num_samps;
|
|
} else {
|
|
/* move pos */
|
|
pos += num_samps;
|
|
while(pos >= SOUND_SHM_SAMP_SIZE) {
|
|
pos -= SOUND_SHM_SAMP_SIZE;
|
|
}
|
|
|
|
if(g_send_sound_to_file) {
|
|
send_sound_to_file(zero_buf, g_sound_shm_pos,
|
|
num_samps);
|
|
}
|
|
|
|
if(g_queued_samps) {
|
|
/* force out old non-0 samps */
|
|
send_sound(1, g_queued_samps);
|
|
g_queued_samps = 0;
|
|
}
|
|
|
|
g_queued_nonsamps += num_samps;
|
|
}
|
|
|
|
}
|
|
|
|
g_sound_shm_pos = pos;
|
|
|
|
|
|
GET_ITIMER(end_time3);
|
|
|
|
g_fvoices += ((float)(samps_played) * (float)(g_drecip_audio_rate));
|
|
|
|
if(g_audio_enable != 0) {
|
|
if(g_queued_samps >= (g_audio_rate/32)) {
|
|
send_sound(1, g_queued_samps);
|
|
g_queued_samps = 0;
|
|
}
|
|
|
|
if(g_queued_nonsamps >= (g_audio_rate/32)) {
|
|
send_sound(0, g_queued_nonsamps);
|
|
g_queued_nonsamps = 0;
|
|
}
|
|
}
|
|
|
|
GET_ITIMER(end_time1);
|
|
|
|
g_cycs_in_sound1 += (end_time1 - start_time1);
|
|
g_cycs_in_sound3 += (end_time3 - start_time3);
|
|
g_cycs_in_sound4 += (start_time2 - start_time4);
|
|
|
|
g_last_sound_play_dsamp = dsamp_now;
|
|
|
|
g_sound_play_depth--;
|
|
}
|
|
|
|
|
|
void
|
|
doc_handle_event(int osc, double dcycs)
|
|
{
|
|
double dsamps;
|
|
|
|
/* handle osc stopping and maybe interrupting */
|
|
|
|
g_num_doc_events++;
|
|
|
|
dsamps = dcycs * g_dsamps_per_dcyc;
|
|
|
|
DOC_LOG("doc_ev", osc, dcycs, 0);
|
|
|
|
g_doc_regs[osc].event = 0;
|
|
|
|
sound_play(dsamps);
|
|
|
|
}
|
|
|
|
void
|
|
doc_sound_end(int osc, int can_repeat, double eff_dsamps, double dsamps)
|
|
{
|
|
Doc_reg *rptr, *orptr;
|
|
int mode, omode;
|
|
int other_osc;
|
|
int one_shot_stop;
|
|
int ctl;
|
|
|
|
/* handle osc stopping and maybe interrupting */
|
|
|
|
if(osc < 0 || osc > 31) {
|
|
printf("doc_handle_event: osc: %d!\n", osc);
|
|
return;
|
|
}
|
|
|
|
rptr = &(g_doc_regs[osc]);
|
|
ctl = rptr->ctl;
|
|
|
|
if(rptr->event) {
|
|
remove_event_doc(osc);
|
|
}
|
|
rptr->event = 0;
|
|
rptr->cur_acc = 0; /* reset internal accumulator*/
|
|
|
|
/* check to make sure osc is running */
|
|
if(ctl & 0x01) {
|
|
/* Oscillator already stopped. */
|
|
halt_printf("Osc %d interrupt, but it was already stop!\n",osc);
|
|
#ifdef HPUX
|
|
U_STACK_TRACE();
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if(ctl & 0x08) {
|
|
if(rptr->has_irq_pending == 0) {
|
|
add_sound_irq(osc);
|
|
}
|
|
}
|
|
|
|
if(!rptr->running) {
|
|
halt_printf("Doc event for osc %d, but ! running\n", osc);
|
|
}
|
|
|
|
rptr->running = 0;
|
|
|
|
mode = (ctl >> 1) & 3;
|
|
other_osc = osc ^ 1;
|
|
orptr = &(g_doc_regs[other_osc]);
|
|
omode = (orptr->ctl >> 1) & 3;
|
|
|
|
/* If either this osc or it's partner is in swap mode, treat the */
|
|
/* pair as being in swap mode. This Ensoniq feature pointed out */
|
|
/* by Ian Schmidt */
|
|
if(mode == 0 && can_repeat) {
|
|
/* free-running mode with no 0 byte! */
|
|
/* start doing it again */
|
|
|
|
start_sound(osc, eff_dsamps, dsamps);
|
|
|
|
return;
|
|
} else if((mode == 3) || (omode == 3)) {
|
|
/* swap mode (even if we're one_shot and partner is swap)! */
|
|
/* unless we're one-shot and we hit a 0-byte--then */
|
|
/* Olivier Goguel says just stop */
|
|
rptr->ctl |= 1;
|
|
one_shot_stop = (mode == 1) && (!can_repeat);
|
|
if(!one_shot_stop && !orptr->running &&
|
|
(orptr->ctl & 0x1)) {
|
|
orptr->ctl = orptr->ctl & (~1);
|
|
start_sound(other_osc, eff_dsamps, dsamps);
|
|
}
|
|
return;
|
|
} else {
|
|
/* stop the oscillator */
|
|
rptr->ctl |= 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
add_sound_irq(int osc)
|
|
{
|
|
int num_osc_interrupting;
|
|
|
|
if(g_doc_regs[osc].has_irq_pending) {
|
|
halt_printf("Adding sound_irq for %02x, but irq_p: %d\n", osc,
|
|
g_doc_regs[osc].has_irq_pending);
|
|
}
|
|
|
|
num_osc_interrupting = g_num_osc_interrupting + 1;
|
|
g_doc_regs[osc].has_irq_pending = num_osc_interrupting;
|
|
g_num_osc_interrupting = num_osc_interrupting;
|
|
|
|
add_irq(IRQ_PENDING_DOC);
|
|
if(num_osc_interrupting == 1) {
|
|
doc_reg_e0 = 0x00 + (osc << 1);
|
|
}
|
|
|
|
DOC_LOG("add_irq", osc, g_cur_dcycs * g_dsamps_per_dcyc, 0);
|
|
}
|
|
|
|
void
|
|
remove_sound_irq(int osc, int must)
|
|
{
|
|
Doc_reg *rptr;
|
|
int num_osc_interrupt;
|
|
int has_irq_pending;
|
|
int first;
|
|
int i;
|
|
|
|
doc_printf("remove irq for osc: %d, has_irq: %d\n",
|
|
osc, g_doc_regs[osc].has_irq_pending);
|
|
|
|
num_osc_interrupt = g_doc_regs[osc].has_irq_pending;
|
|
first = 0;
|
|
if(num_osc_interrupt) {
|
|
g_num_osc_interrupting--;
|
|
g_doc_regs[osc].has_irq_pending = 0;
|
|
DOC_LOG("rem_irq", osc, g_cur_dcycs * g_dsamps_per_dcyc, 0);
|
|
if(g_num_osc_interrupting == 0) {
|
|
remove_irq(IRQ_PENDING_DOC);
|
|
}
|
|
|
|
first = 0x40 | (doc_reg_e0 >> 1);
|
|
/* if none found, then def = no ints */
|
|
for(i = 0; i < g_doc_num_osc_en; i++) {
|
|
rptr = &(g_doc_regs[i]);
|
|
has_irq_pending = rptr->has_irq_pending;
|
|
if(has_irq_pending > num_osc_interrupt) {
|
|
has_irq_pending--;
|
|
rptr->has_irq_pending = has_irq_pending;
|
|
}
|
|
if(has_irq_pending == 1) {
|
|
first = i;
|
|
}
|
|
}
|
|
if(num_osc_interrupt == 1) {
|
|
doc_reg_e0 = (first << 1);
|
|
} else {
|
|
#if 0
|
|
halt_printf("remove_sound_irq[%02x]=%d, first:%d\n",
|
|
osc, num_osc_interrupt, first);
|
|
#endif
|
|
}
|
|
} else {
|
|
#if 0
|
|
/* make sure no int pending */
|
|
if(doc_reg_e0 != 0xff) {
|
|
halt_printf("remove_sound_irq[%02x]=0, but e0: %02x\n",
|
|
osc, doc_reg_e0);
|
|
}
|
|
#endif
|
|
if(must) {
|
|
halt_printf("REMOVE_sound_irq[%02x]=0, but e0: %02x\n",
|
|
osc, doc_reg_e0);
|
|
}
|
|
}
|
|
|
|
if(doc_reg_e0 & 0x80) {
|
|
for(i = 0; i < 0x20; i++) {
|
|
has_irq_pending = g_doc_regs[i].has_irq_pending;
|
|
if(has_irq_pending) {
|
|
halt_printf("remove_sound_irq[%02x], but "
|
|
"[%02x]=%d!\n", osc,i,has_irq_pending);
|
|
printf("num_osc_int: %d, first: %02x\n",
|
|
num_osc_interrupt, first);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
start_sound(int osc, double eff_dsamps, double dsamps)
|
|
{
|
|
register word32 start_time1;
|
|
register word32 end_time1;
|
|
Doc_reg *rptr;
|
|
int ctl;
|
|
int mode;
|
|
word32 sz;
|
|
word32 size;
|
|
word32 wave_size;
|
|
|
|
if(osc < 0 || osc > 31) {
|
|
halt_printf("start_sound: osc: %02x!\n", osc);
|
|
}
|
|
|
|
g_num_start_sounds++;
|
|
|
|
rptr = &(g_doc_regs[osc]);
|
|
|
|
if(osc >= g_doc_num_osc_en) {
|
|
rptr->ctl |= 1;
|
|
return;
|
|
}
|
|
|
|
GET_ITIMER(start_time1);
|
|
|
|
ctl = rptr->ctl;
|
|
|
|
mode = (ctl >> 1) & 3;
|
|
|
|
wave_size = rptr->wavesize;
|
|
|
|
sz = ((wave_size >> 3) & 7) + 8;
|
|
size = 1 << sz;
|
|
|
|
if(size < 0x100) {
|
|
halt_printf("size: %08x is too small, sz: %08x!\n", size, sz);
|
|
}
|
|
|
|
if(rptr->running) {
|
|
halt_printf("start_sound osc: %d, already running!\n", osc);
|
|
}
|
|
|
|
rptr->running = 1;
|
|
|
|
rptr->complete_dsamp = eff_dsamps;
|
|
|
|
doc_printf("Starting osc %02x, dsamp: %f\n", osc, dsamps);
|
|
doc_printf("size: %04x\n", size);
|
|
|
|
if((mode == 2) && ((osc & 1) == 0)) {
|
|
printf("Sync mode osc %d starting!\n", osc);
|
|
/* set_halt(1); */
|
|
|
|
/* see if we should start our odd partner */
|
|
if((rptr[1].ctl & 7) == 5) {
|
|
/* odd partner stopped in sync mode--start him */
|
|
rptr[1].ctl &= (~1);
|
|
start_sound(osc + 1, eff_dsamps, dsamps);
|
|
} else {
|
|
printf("Osc %d starting sync, but osc %d ctl: %02x\n",
|
|
osc, osc+1, rptr[1].ctl);
|
|
}
|
|
}
|
|
|
|
wave_end_estimate(osc, eff_dsamps, dsamps);
|
|
|
|
DOC_LOG("st playing", osc, eff_dsamps, size);
|
|
#if 0
|
|
if(rptr->cur_acc != 0) {
|
|
halt_printf("Start osc %02x, acc: %08x\n", osc, rptr->cur_acc);
|
|
}
|
|
#endif
|
|
|
|
GET_ITIMER(end_time1);
|
|
|
|
g_cycs_in_start_sound += (end_time1 - start_time1);
|
|
}
|
|
|
|
void
|
|
wave_end_estimate(int osc, double eff_dsamps, double dsamps)
|
|
{
|
|
register word32 start_time1;
|
|
register word32 end_time1;
|
|
Doc_reg *rptr;
|
|
byte *ptr1;
|
|
double event_dsamp;
|
|
double event_dcycs;
|
|
double dcycs_per_samp;
|
|
double dsamps_per_byte;
|
|
double num_dsamps;
|
|
double dcur_inc;
|
|
word32 tmp1;
|
|
word32 cur_inc;
|
|
word32 save_val;
|
|
int save_size;
|
|
int pos;
|
|
int size;
|
|
int estimate;
|
|
|
|
GET_ITIMER(start_time1);
|
|
|
|
dcycs_per_samp = g_dcycs_per_samp;
|
|
|
|
rptr = &(g_doc_regs[osc]);
|
|
|
|
cur_inc = rptr->cur_inc;
|
|
dcur_inc = (double)cur_inc;
|
|
dsamps_per_byte = 0.0;
|
|
if(cur_inc) {
|
|
dsamps_per_byte = SND_PTR_SHIFT_DBL / (double)dcur_inc;
|
|
}
|
|
|
|
/* see if there's a zero byte */
|
|
tmp1 = rptr->cur_start + (rptr->cur_acc & rptr->cur_mask);
|
|
pos = tmp1 >> SND_PTR_SHIFT;
|
|
size = ((rptr->cur_end) >> SND_PTR_SHIFT) - pos;
|
|
|
|
ptr1 = &doc_ram[pos];
|
|
|
|
estimate = 0;
|
|
if(rptr->ctl & 0x08 || g_doc_regs[osc ^ 1].ctl & 0x08) {
|
|
estimate = 1;
|
|
}
|
|
|
|
#if 0
|
|
estimate = 1;
|
|
#endif
|
|
if(estimate) {
|
|
save_size = size;
|
|
save_val = ptr1[size];
|
|
ptr1[size] = 0;
|
|
size = strlen((char *)ptr1);
|
|
ptr1[save_size] = save_val;
|
|
}
|
|
|
|
/* calc samples to play */
|
|
num_dsamps = (dsamps_per_byte * (double)size) + 1.0;
|
|
|
|
rptr->samps_left = (int)num_dsamps;
|
|
|
|
if(rptr->event) {
|
|
remove_event_doc(osc);
|
|
}
|
|
rptr->event = 0;
|
|
|
|
event_dsamp = eff_dsamps + num_dsamps;
|
|
if(estimate) {
|
|
rptr->event = 1;
|
|
rptr->dsamp_ev = event_dsamp;
|
|
rptr->dsamp_ev2 = dsamps;
|
|
event_dcycs = (event_dsamp * dcycs_per_samp) + 1.0;
|
|
add_event_doc(event_dcycs, osc);
|
|
}
|
|
|
|
GET_ITIMER(end_time1);
|
|
|
|
g_cycs_in_est_sound += (end_time1 - start_time1);
|
|
}
|
|
|
|
|
|
void
|
|
remove_sound_event(int osc)
|
|
{
|
|
if(g_doc_regs[osc].event) {
|
|
g_doc_regs[osc].event = 0;
|
|
remove_event_doc(osc);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
doc_write_ctl_reg(int osc, int val, double dsamps)
|
|
{
|
|
Doc_reg *rptr;
|
|
double eff_dsamps;
|
|
word32 old_halt;
|
|
word32 new_halt;
|
|
int old_val;
|
|
int mode;
|
|
|
|
if(osc < 0 || osc >= 0x20) {
|
|
halt_printf("doc_write_ctl_reg: osc: %02x, val: %02x\n",
|
|
osc, val);
|
|
return;
|
|
}
|
|
|
|
eff_dsamps = dsamps;
|
|
rptr = &(g_doc_regs[osc]);
|
|
old_val = rptr->ctl;
|
|
g_doc_saved_ctl = old_val;
|
|
|
|
if(old_val == val) {
|
|
return;
|
|
}
|
|
|
|
DOC_LOG("ctl_reg", osc, dsamps, (old_val << 16) + val);
|
|
|
|
mode = (val >> 1) & 3;
|
|
|
|
old_halt = (old_val & 1);
|
|
new_halt = (val & 1);
|
|
|
|
/* bits are: 28: old int bit */
|
|
/* 29: old halt bit */
|
|
/* 30: new int bit */
|
|
/* 31: new halt bit */
|
|
|
|
#if 0
|
|
if(osc == 0x10) {
|
|
printf("osc %d new_ctl: %02x, old: %02x\n", osc, val, old_val);
|
|
}
|
|
#endif
|
|
|
|
/* no matter what, remove any pending IRQs on this osc */
|
|
remove_sound_irq(osc, 0);
|
|
|
|
#if 0
|
|
if(old_halt) {
|
|
printf("doc_write_ctl to osc %d, val: %02x, old: %02x\n",
|
|
osc, val, old_val);
|
|
}
|
|
#endif
|
|
|
|
if(new_halt != 0) {
|
|
/* make sure sound is stopped */
|
|
remove_sound_event(osc);
|
|
if(old_halt == 0) {
|
|
/* it was playing, finish it up */
|
|
#if 0
|
|
halt_printf("Aborted osc %d at eff_dsamps: %f, ctl: "
|
|
"%02x, oldctl: %02x\n", osc, eff_dsamps,
|
|
val, old_val);
|
|
#endif
|
|
sound_play(eff_dsamps);
|
|
}
|
|
if(((old_val >> 1) & 3) > 0) {
|
|
/* don't clear acc if free-running */
|
|
g_doc_regs[osc].cur_acc = 0;
|
|
}
|
|
|
|
g_doc_regs[osc].ctl = val;
|
|
g_doc_regs[osc].running = 0;
|
|
} else {
|
|
/* new halt == 0 = make sure sound is running */
|
|
if(old_halt != 0) {
|
|
/* start sound */
|
|
DOC_LOG("ctl_sound_play", osc, eff_dsamps, val);
|
|
sound_play(eff_dsamps);
|
|
g_doc_regs[osc].ctl = val;
|
|
|
|
start_sound(osc, eff_dsamps, dsamps);
|
|
} else {
|
|
/* was running, and something changed */
|
|
doc_printf("osc %d old ctl:%02x new:%02x!\n",
|
|
osc, old_val, val);
|
|
#if 0
|
|
sound_play(eff_dsamps);
|
|
/* HACK: fix this??? */
|
|
#endif
|
|
g_doc_regs[osc].ctl = val;
|
|
if((old_val ^ val) & val & 0x8) {
|
|
/* now has ints on */
|
|
wave_end_estimate(osc, dsamps, dsamps);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
doc_recalc_sound_parms(int osc, double eff_dcycs, double dsamps)
|
|
{
|
|
Doc_reg *rptr;
|
|
double dfreq;
|
|
double dtmp1;
|
|
double dacc, dacc_recip;
|
|
word32 res;
|
|
word32 sz;
|
|
word32 size;
|
|
word32 wave_size;
|
|
word32 cur_start;
|
|
word32 shifted_size;
|
|
|
|
g_num_recalc_snd_parms++;
|
|
|
|
rptr = &(g_doc_regs[osc]);
|
|
|
|
wave_size = rptr->wavesize;
|
|
|
|
dfreq = (double)rptr->freq;
|
|
|
|
sz = ((wave_size >> 3) & 7) + 8;
|
|
size = 1 << sz;
|
|
rptr->size_bytes = size;
|
|
res = wave_size & 7;
|
|
|
|
shifted_size = size << SND_PTR_SHIFT;
|
|
cur_start = (rptr->waveptr << (8 + SND_PTR_SHIFT)) & (-shifted_size);
|
|
|
|
dtmp1 = dfreq * (DOC_SCAN_RATE * g_drecip_audio_rate);
|
|
dacc = (double)(1 << (20 - (17 - sz + res)));
|
|
dacc_recip = (SND_PTR_SHIFT_DBL) / ((double)(1 << 20));
|
|
dtmp1 = dtmp1 * g_drecip_osc_en_plus_2 * dacc * dacc_recip;
|
|
|
|
rptr->cur_inc = (int)(dtmp1);
|
|
rptr->cur_start = cur_start;
|
|
rptr->cur_end = cur_start + shifted_size;
|
|
rptr->cur_mask = (shifted_size - 1);
|
|
|
|
DOC_LOG("recalc", osc, dsamps, (rptr->waveptr << 16) + wave_size);
|
|
}
|
|
|
|
int
|
|
doc_read_c030(double dcycs)
|
|
{
|
|
int num;
|
|
|
|
num = g_num_c030_fsamps;
|
|
if(num >= MAX_C030_TIMES) {
|
|
halt_printf("Too many clicks per vbl: %d\n", num);
|
|
return 0;
|
|
}
|
|
|
|
c030_fsamps[num] = (float)(dcycs * g_dsamps_per_dcyc -
|
|
g_last_sound_play_dsamp);
|
|
g_num_c030_fsamps = num + 1;
|
|
|
|
doc_printf("read c030, num this vbl: %04x\n", num);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
doc_read_c03c(double dcycs)
|
|
{
|
|
return doc_sound_ctl;
|
|
}
|
|
|
|
int
|
|
doc_read_c03d(double dcycs)
|
|
{
|
|
double dsamps;
|
|
Doc_reg *rptr;
|
|
int osc;
|
|
int type;
|
|
int ret;
|
|
|
|
ret = doc_saved_val;
|
|
dsamps = dcycs * g_dsamps_per_dcyc;
|
|
|
|
if(doc_sound_ctl & 0x40) {
|
|
/* Read RAM */
|
|
doc_saved_val = doc_ram[g_c03ef_doc_ptr];
|
|
} else {
|
|
/* Read DOC */
|
|
doc_saved_val = 0;
|
|
|
|
osc = g_c03ef_doc_ptr & 0x1f;
|
|
type = (g_c03ef_doc_ptr >> 5) & 0x7;
|
|
rptr = &(g_doc_regs[osc]);
|
|
|
|
switch(type) {
|
|
case 0x0: /* freq lo */
|
|
doc_saved_val = rptr->freq & 0xff;
|
|
break;
|
|
case 0x1: /* freq hi */
|
|
doc_saved_val = rptr->freq >> 8;
|
|
break;
|
|
case 0x2: /* vol */
|
|
doc_saved_val = rptr->vol;
|
|
break;
|
|
case 0x3: /* data register */
|
|
/* HACK: make this call sound_play sometimes */
|
|
doc_saved_val = rptr->last_samp_val;
|
|
break;
|
|
case 0x4: /* wave ptr register */
|
|
doc_saved_val = rptr->waveptr;
|
|
break;
|
|
case 0x5: /* control register */
|
|
doc_saved_val = rptr->ctl;
|
|
break;
|
|
case 0x6: /* control register */
|
|
doc_saved_val = rptr->wavesize;
|
|
break;
|
|
case 0x7: /* 0xe0-0xff */
|
|
switch(osc) {
|
|
case 0x00: /* 0xe0 */
|
|
doc_saved_val = doc_reg_e0;
|
|
doc_printf("Reading doc 0xe0, ret: %02x\n",
|
|
doc_saved_val);
|
|
|
|
/* Clear IRQ on read of e0, if any irq pend */
|
|
if((doc_reg_e0 & 0x80) == 0) {
|
|
remove_sound_irq(doc_reg_e0 >> 1, 1);
|
|
}
|
|
break;
|
|
case 0x01: /* 0xe1 */
|
|
doc_saved_val = (g_doc_num_osc_en - 1) << 1;
|
|
break;
|
|
case 0x02: /* 0xe2 */
|
|
doc_saved_val = 0x80;
|
|
#if 0
|
|
halt_printf("Reading doc 0xe2, ret: %02x\n",
|
|
doc_saved_val);
|
|
#endif
|
|
break;
|
|
default:
|
|
doc_saved_val = 0;
|
|
halt_printf("Reading bad doc_reg[%04x]: %02x\n",
|
|
g_c03ef_doc_ptr, doc_saved_val);
|
|
}
|
|
break;
|
|
default:
|
|
doc_saved_val = 0;
|
|
halt_printf("Reading bad doc_reg[%04x]: %02x\n",
|
|
g_c03ef_doc_ptr, doc_saved_val);
|
|
}
|
|
}
|
|
|
|
doc_printf("read c03d, doc_ptr: %04x, ret: %02x, saved: %02x\n",
|
|
g_c03ef_doc_ptr, ret, doc_saved_val);
|
|
|
|
DOC_LOG("read c03d", -1, dsamps, (g_c03ef_doc_ptr << 16) +
|
|
(doc_saved_val << 8) + ret);
|
|
|
|
if(doc_sound_ctl & 0x20) {
|
|
g_c03ef_doc_ptr = (g_c03ef_doc_ptr + 1) & 0xffff;
|
|
}
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
doc_write_c03c(int val, double dcycs)
|
|
{
|
|
int vol;
|
|
|
|
vol = val & 0xf;
|
|
if(g_doc_vol != vol) {
|
|
/* don't bother playing sound..wait till next update */
|
|
/* sound_play(dcycs); */
|
|
|
|
g_doc_vol = vol;
|
|
doc_printf("Setting doc vol to 0x%x at %f\n",
|
|
vol, dcycs);
|
|
}
|
|
DOC_LOG("c03c write", -1, dcycs * g_dsamps_per_dcyc, val);
|
|
|
|
doc_sound_ctl = val;
|
|
}
|
|
|
|
void
|
|
doc_write_c03d(int val, double dcycs)
|
|
{
|
|
double dsamps;
|
|
double eff_dsamps;
|
|
Doc_reg *rptr;
|
|
int osc;
|
|
int type;
|
|
int ctl;
|
|
int tmp;
|
|
int i;
|
|
|
|
val = val & 0xff;
|
|
|
|
dsamps = dcycs * g_dsamps_per_dcyc;
|
|
eff_dsamps = dsamps;
|
|
doc_printf("write c03d, doc_ptr: %04x, val: %02x\n",
|
|
g_c03ef_doc_ptr, val);
|
|
|
|
DOC_LOG("write c03d", -1, dsamps, (g_c03ef_doc_ptr << 16) + val);
|
|
|
|
if(doc_sound_ctl & 0x40) {
|
|
/* RAM */
|
|
doc_ram[g_c03ef_doc_ptr] = val;
|
|
} else {
|
|
/* DOC */
|
|
osc = g_c03ef_doc_ptr & 0x1f;
|
|
type = (g_c03ef_doc_ptr >> 5) & 0x7;
|
|
|
|
rptr = &(g_doc_regs[osc]);
|
|
ctl = rptr->ctl;
|
|
#if 0
|
|
if((ctl & 1) == 0) {
|
|
if(type < 2 || type == 4 || type == 6) {
|
|
halt_printf("Osc %d is running, old ctl: %02x, "
|
|
"but write reg %02x=%02x\n",
|
|
osc, ctl, g_c03ef_doc_ptr & 0xff, val);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
switch(type) {
|
|
case 0x0: /* freq lo */
|
|
if((rptr->freq & 0xff) == (word32)val) {
|
|
break;
|
|
}
|
|
if((ctl & 1) == 0) {
|
|
/* play through current status */
|
|
DOC_LOG("flo_sound_play", osc, dsamps, val);
|
|
sound_play(dsamps);
|
|
}
|
|
rptr->freq = (rptr->freq & 0xff00) + val;
|
|
doc_recalc_sound_parms(osc, eff_dsamps, dsamps);
|
|
break;
|
|
case 0x1: /* freq hi */
|
|
if((rptr->freq >> 8) == (word32)val) {
|
|
break;
|
|
}
|
|
if((ctl & 1) == 0) {
|
|
/* play through current status */
|
|
DOC_LOG("fhi_sound_play", osc, dsamps, val);
|
|
sound_play(dsamps);
|
|
}
|
|
rptr->freq = (rptr->freq & 0xff) + (val << 8);
|
|
doc_recalc_sound_parms(osc, eff_dsamps, dsamps);
|
|
break;
|
|
case 0x2: /* vol */
|
|
if(rptr->vol == (word32)val) {
|
|
break;
|
|
}
|
|
if((ctl & 1) == 0) {
|
|
/* play through current status */
|
|
DOC_LOG("vol_sound_play", osc, dsamps, val);
|
|
sound_play(dsamps);
|
|
#if 0
|
|
halt_printf("vol_sound_play at %.1f osc:%d "
|
|
"val:%d\n", dsamps, osc, val);
|
|
#endif
|
|
}
|
|
rptr->vol = val;
|
|
break;
|
|
case 0x3: /* data register */
|
|
#if 0
|
|
printf("Writing %02x into doc_data_reg[%02x]!\n",
|
|
val, osc);
|
|
#endif
|
|
break;
|
|
case 0x4: /* wave ptr register */
|
|
if(rptr->waveptr == (word32)val) {
|
|
break;
|
|
}
|
|
if((ctl & 1) == 0) {
|
|
/* play through current status */
|
|
DOC_LOG("wptr_sound_play", osc, dsamps, val);
|
|
sound_play(dsamps);
|
|
}
|
|
rptr->waveptr = val;
|
|
doc_recalc_sound_parms(osc, eff_dsamps, dsamps);
|
|
break;
|
|
case 0x5: /* control register */
|
|
#if 0
|
|
printf("doc_write ctl osc %d, val: %02x\n", osc, val);
|
|
#endif
|
|
if(rptr->ctl == (word32)val) {
|
|
break;
|
|
}
|
|
doc_write_ctl_reg(osc, val, dsamps);
|
|
break;
|
|
case 0x6: /* wavesize register */
|
|
if(rptr->wavesize == (word32)val) {
|
|
break;
|
|
}
|
|
if((ctl & 1) == 0) {
|
|
/* play through current status */
|
|
DOC_LOG("wsz_sound_play", osc, dsamps, val);
|
|
sound_play(dsamps);
|
|
}
|
|
rptr->wavesize = val;
|
|
doc_recalc_sound_parms(osc, eff_dsamps, dsamps);
|
|
break;
|
|
case 0x7: /* 0xe0-0xff */
|
|
switch(osc) {
|
|
case 0x00: /* 0xe0 */
|
|
doc_printf("writing doc 0xe0 with %02x, "
|
|
"was:%02x\n", val, doc_reg_e0);
|
|
#if 0
|
|
if(val != doc_reg_e0) {
|
|
halt_printf("writing doc 0xe0 with "
|
|
"%02x, was:%02x\n", val,
|
|
doc_reg_e0);
|
|
}
|
|
#endif
|
|
break;
|
|
case 0x01: /* 0xe1 */
|
|
doc_printf("Writing doc 0xe1 with %02x\n", val);
|
|
tmp = val & 0x3e;
|
|
tmp = (tmp >> 1) + 1;
|
|
if(tmp < 1) {
|
|
tmp = 1;
|
|
}
|
|
if(tmp > 32) {
|
|
halt_printf("doc 0xe1: %02x!\n", val);
|
|
tmp = 32;
|
|
}
|
|
g_doc_num_osc_en = tmp;
|
|
UPDATE_G_DCYCS_PER_DOC_UPDATE(tmp);
|
|
|
|
/* Stop any oscs that were running but now */
|
|
/* are disabled */
|
|
for(i = g_doc_num_osc_en; i < 0x20; i++) {
|
|
doc_write_ctl_reg(i,
|
|
g_doc_regs[i].ctl | 1, dsamps);
|
|
}
|
|
|
|
break;
|
|
default:
|
|
/* this should be illegal, but Turkey Shoot */
|
|
/* and apparently TaskForce, OOTW, etc */
|
|
/* writes to e2-ff, for no apparent reason */
|
|
doc_printf("Writing doc 0x%x with %02x\n",
|
|
g_c03ef_doc_ptr, val);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
halt_printf("Writing %02x into bad doc_reg[%04x]\n",
|
|
val, g_c03ef_doc_ptr);
|
|
}
|
|
}
|
|
|
|
if(doc_sound_ctl & 0x20) {
|
|
g_c03ef_doc_ptr = (g_c03ef_doc_ptr + 1) & 0xffff;
|
|
}
|
|
|
|
doc_saved_val = val;
|
|
}
|
|
|
|
void
|
|
doc_show_ensoniq_state(int osc)
|
|
{
|
|
Doc_reg *rptr;
|
|
int i;
|
|
|
|
printf("Ensoniq state\n");
|
|
printf("c03c doc_sound_ctl: %02x, doc_saved_val: %02x\n",
|
|
doc_sound_ctl, doc_saved_val);
|
|
printf("doc_ptr: %04x, num_osc_en: %02x, e0: %02x\n",
|
|
g_c03ef_doc_ptr, g_doc_num_osc_en, doc_reg_e0);
|
|
|
|
for(i = 0; i < 32; i += 8) {
|
|
printf("irqp: %02x: %04x %04x %04x %04x %04x %04x %04x %04x\n",
|
|
i,
|
|
g_doc_regs[i].has_irq_pending,
|
|
g_doc_regs[i + 1].has_irq_pending,
|
|
g_doc_regs[i + 2].has_irq_pending,
|
|
g_doc_regs[i + 3].has_irq_pending,
|
|
g_doc_regs[i + 4].has_irq_pending,
|
|
g_doc_regs[i + 5].has_irq_pending,
|
|
g_doc_regs[i + 6].has_irq_pending,
|
|
g_doc_regs[i + 7].has_irq_pending);
|
|
}
|
|
|
|
for(i = 0; i < 32; i += 8) {
|
|
printf("freq: %02x: %04x %04x %04x %04x %04x %04x %04x %04x\n",
|
|
i,
|
|
g_doc_regs[i].freq, g_doc_regs[i + 1].freq,
|
|
g_doc_regs[i + 2].freq, g_doc_regs[i + 3].freq,
|
|
g_doc_regs[i + 4].freq, g_doc_regs[i + 5].freq,
|
|
g_doc_regs[i + 6].freq, g_doc_regs[i + 7].freq);
|
|
}
|
|
|
|
for(i = 0; i < 32; i += 8) {
|
|
printf("vol: %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
i,
|
|
g_doc_regs[i].vol, g_doc_regs[i + 1].vol,
|
|
g_doc_regs[i + 2].vol, g_doc_regs[i + 3].vol,
|
|
g_doc_regs[i + 4].vol, g_doc_regs[i + 5].vol,
|
|
g_doc_regs[i + 6].vol, g_doc_regs[i + 6].vol);
|
|
}
|
|
|
|
for(i = 0; i < 32; i += 8) {
|
|
printf("wptr: %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
i,
|
|
g_doc_regs[i].waveptr, g_doc_regs[i + 1].waveptr,
|
|
g_doc_regs[i + 2].waveptr, g_doc_regs[i + 3].waveptr,
|
|
g_doc_regs[i + 4].waveptr, g_doc_regs[i + 5].waveptr,
|
|
g_doc_regs[i + 6].waveptr, g_doc_regs[i + 7].waveptr);
|
|
}
|
|
|
|
for(i = 0; i < 32; i += 8) {
|
|
printf("ctl: %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
i,
|
|
g_doc_regs[i].ctl, g_doc_regs[i + 1].ctl,
|
|
g_doc_regs[i + 2].ctl, g_doc_regs[i + 3].ctl,
|
|
g_doc_regs[i + 4].ctl, g_doc_regs[i + 5].ctl,
|
|
g_doc_regs[i + 6].ctl, g_doc_regs[i + 7].ctl);
|
|
}
|
|
|
|
for(i = 0; i < 32; i += 8) {
|
|
printf("wsize: %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
i,
|
|
g_doc_regs[i].wavesize, g_doc_regs[i + 1].wavesize,
|
|
g_doc_regs[i + 2].wavesize, g_doc_regs[i + 3].wavesize,
|
|
g_doc_regs[i + 4].wavesize, g_doc_regs[i + 5].wavesize,
|
|
g_doc_regs[i + 6].wavesize, g_doc_regs[i + 7].wavesize);
|
|
}
|
|
|
|
show_doc_log();
|
|
|
|
for(i = 0; i < 32; i++) {
|
|
rptr = &(g_doc_regs[i]);
|
|
printf("%2d: ctl:%02x wp:%02x ws:%02x freq:%04x vol:%02x "
|
|
"ev:%d run:%d irq:%d sz:%04x\n", i,
|
|
rptr->ctl, rptr->waveptr, rptr->wavesize, rptr->freq,
|
|
rptr->vol, rptr->event, rptr->running,
|
|
rptr->has_irq_pending, rptr->size_bytes);
|
|
printf(" acc:%08x inc:%08x st:%08x end:%08x m:%08x\n",
|
|
rptr->cur_acc, rptr->cur_inc, rptr->cur_start,
|
|
rptr->cur_end, rptr->cur_mask);
|
|
printf(" compl_ds:%f samps_left:%d ev:%f ev2:%f\n",
|
|
rptr->complete_dsamp, rptr->samps_left,
|
|
rptr->dsamp_ev, rptr->dsamp_ev2);
|
|
}
|
|
|
|
#if 0
|
|
for(osc = 0; osc < 32; osc++) {
|
|
fmax = 0.0;
|
|
printf("osc %d has %d samps\n", osc, g_fsamp_num[osc]);
|
|
for(i = 0; i < g_fsamp_num[osc]; i++) {
|
|
printf("%4d: %f\n", i, g_fsamps[osc][i]);
|
|
fmax = MAX(fmax, g_fsamps[osc][i]);
|
|
}
|
|
printf("osc %d, fmax: %f\n", osc, fmax);
|
|
}
|
|
#endif
|
|
}
|