/************************************************************************/ /* 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) 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) int pid; int shmid; int tmp; int i; #endif word32 *shmaddr; int size; int ret; #if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC) 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) 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__) /* 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]); #else # ifdef MAC macsnd_init(shmaddr); # else /* windows */ win32snd_init(shmaddr); # endif #endif /* _WIN32 */ } 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) 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 }