2011-01-16 22:52:06 +00:00
/*
GSport - an Apple //gs Emulator
2012-02-29 17:37:44 +00:00
Copyright ( C ) 2010 - 2012 by GSport contributors
2011-01-16 22:52:06 +00:00
Based on the KEGS emulator written by and Copyright ( C ) 2003 Kent Dickey
This program is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation ; either version 2 of the License , or ( at your
option ) any later version .
This program is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
for more details .
You should have received a copy of the GNU General Public License along
with this program ; if not , write to the Free Software Foundation , Inc . ,
59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "defc.h"
# include "sound.h"
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(WIN_SOUND) || defined(MAC) /* Workaround - gcc in cygwin wasn't defining _WIN32, substituted WIN_SOUND instead */
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 ;
}
// OG sound globals initialization
g_num_c030_fsamps = 0 ;
g_sound_shm_pos = 0 ;
g_queued_samps = 0 ;
g_queued_nonsamps = 0 ;
doc_sound_ctl = 0 ;
doc_saved_val = 0 ;
g_doc_num_osc_en = 1 ;
g_dcycs_per_doc_update = 1.0 ;
g_dupd_per_dcyc = 1.0 ;
g_drecip_osc_en_plus_2 = 1.0 / ( double ) ( 1 + 2 ) ;
doc_reg_e0 = 0xff ;
g_audio_rate = 0 ;
g_daudio_rate = 0.0 ;
g_drecip_audio_rate = 0.0 ;
g_dsamps_per_dcyc = 0.0 ;
g_dcycs_per_samp = 0.0 ;
g_fsamps_per_dcyc = 0.0 ;
g_doc_vol = 2 ;
g_last_sound_play_dsamp = 0.0 ;
sound_init_general ( ) ;
}
void
sound_init_general ( )
{
# if !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__OS2__) /* Workaround - gcc in cygwin wasn't defining _WIN32 */
int pid ;
int shmid ;
int tmp ;
int i ;
# endif
word32 * shmaddr ;
int size ;
int ret ;
# if !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__OS2__) /* Workaround - gcc in cygwin wasn't defining _WIN32 */
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(WIN_SOUND) && !defined(__CYGWIN__) && !defined(MAC) && !defined(__OS2__) /* Workaround - gcc in cygwin wasn't defining _WIN32 */
shmid = shmget ( IPC_PRIVATE , size , IPC_CREAT | 0777 ) ;
if ( shmid < 0 ) {
printf ( " sound_init: shmget ret: %d, errno: %d \n " , shmid ,
errno ) ;
exit ( 2 ) ;
}
2012-02-24 22:23:00 +00:00
shmaddr = ( word32 * ) shmat ( shmid , 0 , 0 ) ;
2011-01-16 22:52:06 +00:00
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 = ( word32 * ) malloc ( size ) ;
memset ( shmaddr , 0 , size ) ;
# endif
g_sound_shm_addr = shmaddr ;
fflush ( stdout ) ;
# if !defined(MAC) && !defined(WIN_SOUND) && !defined(__CYGWIN__) && !defined(__OS2__) /* Workaround - gcc in cygwin wasn't defining _WIN32 */
/* 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 ) ;
# elif defined (WIN_SOUND) /* Workaround - gcc in cygwin wasn't defining _WIN32 */
/* windows */
win32snd_init ( shmaddr ) ;
# elif defined (__OS2__)
# endif
# endif /* WIN_SOUND */
}
void
parent_sound_get_sample_rate ( int read_fd )
{
# ifndef __OS2__
word32 tmp ;
int ret ;
ret = read ( read_fd , ( char * ) & tmp , 4 ) ;
if ( ret ! = 4 ) {
printf ( " parent could not get audio sample rate from child, disabling sound. \n " ) ;
printf ( " ret: %d, fd: %d errno:%d \n " , ret , read_fd , errno ) ;
g_audio_enable = 0 ;
}
close ( read_fd ) ;
set_audio_rate ( tmp ) ;
# endif
}
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 ;
// OG No reason to reset the number of active oscillo on reset : this should only be done on startup.
/*
g_doc_num_osc_en = 1 ;
UPDATE_G_DCYCS_PER_DOC_UPDATE ( 1 ) ;
*/
}
void
sound_shutdown ( )
{
// OG stop sound and free memory on sound_shutdown
sound_reset ( g_cur_dcycs ) ;
# ifdef WIN_SOUND /* Workaround - gcc in cygwin wasn't defining _WIN32 */
win32snd_shutdown ( ) ;
# elif defined(__OS2__)
# else
if ( ( g_audio_enable ! = 0 ) & & g_pipe_fd [ 1 ] ! = 0 ) {
close ( g_pipe_fd [ 1 ] ) ;
}
# endif
// OG Free up allocated memory
if ( g_sound_shm_addr )
{
free ( g_sound_shm_addr ) ;
g_sound_shm_addr = NULL ;
}
}
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 ;
FILE * g_sound_file_fd = 0 ;
int g_send_sound_to_file = 0 ;
int g_send_file_bytes = 0 ;
void
open_sound_file ( )
{
char name [ 256 ] ;
FILE * fd ;
sprintf ( name , " snd.out.%d " , g_sound_file_num ) ;
fd = fopen ( name , " wb+ " ) ;
if ( fd = = 0 ) {
printf ( " open_sound_file open errno: %d \n " , 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 ) {
fclose ( g_sound_file_fd ) ;
}
g_sound_file_fd = 0 ;
}
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 = fwrite ( & ( addr [ shm_pos ] ) , 1 , 4 * size , g_sound_file_fd ) ;
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 = fwrite ( & ( addr [ shm_pos ] ) , 1 , 4 * num_samps , g_sound_file_fd ) ;
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(WIN_SOUND) /* Workaround - gcc in cygwin wasn't defining _WIN32 */
ret = 0 ;
child_sound_playit ( tmp ) ;
# elif defined(__OS2__)
# 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 = ( float ) ( int ) ( fsampnum + 1.0f ) ; //OG added cast
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 */
2012-02-29 17:37:44 +00:00
# if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command
2011-01-16 22:52:06 +00:00
sndptr [ pos ] = ( val < < 16 ) + ( val0 & 0xffff ) ;
# else
sndptr [ pos ] = ( ( val & 0xff ) < < 24 ) +
( ( val & 0xff00 ) < < 8 ) +
( ( val0 & 0xff ) < < 8 ) +
( ( val0 > > 8 ) & 0xff ) ;
# endif
# else
2012-02-29 17:37:44 +00:00
# if defined(GSPORT_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command
2011-01-16 22:52:06 +00:00
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 ) ;
// OG If the sound_play is executed, it may restart a oscillo we thought was stopped at time,
// hence crashing the start_sound function (cf. game Arrgh!)
//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 ) ) & ( - ( int ) shifted_size ) ; // OG
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 ) ;
// OG Update any oscs that were running to take care of the new numbers of oscillo
for ( i = 0 ; i < g_doc_num_osc_en ; i + + )
doc_recalc_sound_parms ( i , 0.0 , 0.0 ) ;
/* 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
}