|
From: <sba...@us...> - 2023-10-01 06:41:57
|
This is an automated email from the git hooks/post-receive-user script. sbaldovi pushed a commit to branch patches-142-currah-uspeech in repository fuse. View the commit online: https://sourceforge.net/p/fuse-emulator/fuse/ci/404a9b53743d15f7d5e37e3c4407ba5f8695946b/ commit 404a9b53743d15f7d5e37e3c4407ba5f8695946b Author: Sergio Baldoví <ser...@gm...> AuthorDate: Tue Sep 26 04:11:55 2023 +0200 uSpeech intonation changes SP0256 clock frequency This patch improves intonation as Kio and Thomas Busse determined that oscillator frequency for low intonation is about 3.05 MHz and high intonation is 7% higher, i.e., 3.26 MHz. As SP0256 and Z80 have different clocks, sample duration is based on Z80 processor speed to ease synchronisation with spectrum frames. --- peripherals/sound/sp0256.c | 63 +++++++++++++++++++++++++++++++++++---------- peripherals/sound/sp0256.h | 3 ++- peripherals/sound/uspeech.c | 17 +++++++++--- 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/peripherals/sound/sp0256.c b/peripherals/sound/sp0256.c index b47f75b7..222d8595 100644 --- a/peripherals/sound/sp0256.c +++ b/peripherals/sound/sp0256.c @@ -116,6 +116,9 @@ typedef struct sp0256_t { uint16_t fifo[64]; /* The 64-decle FIFO. */ const uint8_t *rom[16]; /* 4K ROM pages. */ + + uint32_t clock; /* Clock - crystal frequency */ + unsigned int clock_per_samp; /* Sample duration in Z80 tstates */ } sp0256_t; @@ -140,8 +143,6 @@ static void sp0256_write_ald( sp0256_t *s, uint32_t data ); /* ======================================================================== */ static int sp0256_do_init( sp0256_t *s, uint8_t *sp0256rom ); -static int factor = 358; - /* ======================================================================== */ /* Internal function prototypes. */ /* ======================================================================== */ @@ -1164,7 +1165,8 @@ sp0256_run( sp0256_t *s, uint32_t len ) /* Calculate the number of samples required at ~10kHz. */ /* (Actually, on NTSC this is 3579545 / 358, or 9998.73 Hz). */ /* ---------------------------------------------------------------- */ - samples = ( (int)( until - s->sound_current + factor - 1 ) ) / factor; + samples = ( (int)( until - s->sound_current + s->clock_per_samp - 1 ) ) + / s->clock_per_samp; /* ---------------------------------------------------------------- */ /* Process the current set of filter coefficients as long as the */ @@ -1210,13 +1212,13 @@ sp0256_run( sp0256_t *s, uint32_t len ) if( did_samp ) { int i; for( i = 0; i < did_samp; i++ ) { - sound_sp0256_write( sp0256_tstates + ( ( n + i ) * factor ), + sound_sp0256_write( sp0256_tstates + ( ( n + i ) * s->clock_per_samp ), s->scratch[( i + old_idx ) & SCBUF_MASK] ); } n += did_samp; } - s->sound_current += did_samp * factor; + s->sound_current += did_samp * s->clock_per_samp; } if( s->sound_current < sp0256_now ) { @@ -1325,11 +1327,15 @@ sp0256_do_init( sp0256_t *s, uint8_t *sp0256rom ) ROM for "page" 1 only */ s->rom[1] = sp0256rom; + /* Set nominal crystal clock at 3.12 MHz */ + s->clock = 3120000; + + /* Nominal sample duration of 350 tstates on a Z80 3.50 MHz */ + s->clock_per_samp = 350; + return 0; } -static int current_intonation = 0; - #ifdef DEBUG_USPEECH_ALLOPHONE struct allophone_t { const char *name; @@ -1488,15 +1494,44 @@ sp0256_play( int a ) } void -sp0256_set_intonation( int intonation ) +sp0256_set_clock( uint32_t clock ) +{ + unsigned int samples; + libspectrum_dword processor_speed; + + /* CPC wiki states: + The SP0256 is (usually) driven by a 3.12MHz oscillator, and it uses + 7bit PWM output, which is clocked at 3.12MHz/2, to obtain a 10kHz + sample rate, the chip issues some dummy steps with constant LOW level + additionally to the 128 steps needed for 7bit PWM, making it a total + number of 156 steps per sample. + */ + sp0256.clock = clock; + + /* SP0256 sample rate: + A nominal 3.12 MHz XTAL would produce 10000 samples (10 kHz). + With uSpeech (normal intonation), a 3.05 MHz XTAL would produce 9775 samples. + With uSpeech (high intonation), a 3.26 MHz XTAL would produce 10448 samples. + */ + samples = sp0256.clock / 312.0; + + processor_speed = ( machine_current == NULL ) ? 3500000 : + machine_current->timings.processor_speed; + + /* Z80 sample rate (examples with Z80 clocked at 3.5 MHz): + - A SP0256 sample at 3.12 MHz would last 350 (Z80) t-states. + - A SP0256 sample at 3.05 MHz would last 358 (Z80) t-states. + - A SP0256 sample at 3.26 MHz would last 334 (Z80) t-states. + */ + sp0256.clock_per_samp = processor_speed / samples; +} + +void +sp0256_change_clock( uint32_t clock ) { - if( intonation != current_intonation ) { + if( sp0256.clock != clock ) { sp0256_run_to( &sp0256, tstates ); - debug_printf( ( "sp0256: intonation %s\n", - intonation ? "high" : "normal" ) ); - current_intonation = intonation; - /* 358 - 1/8th = 314 */ - factor = intonation ? 314 : 358; + sp0256_set_clock( clock ); } } diff --git a/peripherals/sound/sp0256.h b/peripherals/sound/sp0256.h index afde6f87..6185db43 100644 --- a/peripherals/sound/sp0256.h +++ b/peripherals/sound/sp0256.h @@ -32,7 +32,8 @@ int sp0256_reset( uint8_t *sp0256rom ); void sp0256_end( void ); void sp0256_play( int allophone ); -void sp0256_set_intonation( int intonation ); +void sp0256_set_clock( uint32_t clock ); +void sp0256_change_clock( uint32_t clock ); int sp0256_busy( void ); void sp0256_do_frame( void ); diff --git a/peripherals/sound/uspeech.c b/peripherals/sound/uspeech.c index aae1b91a..b05cf5f7 100644 --- a/peripherals/sound/uspeech.c +++ b/peripherals/sound/uspeech.c @@ -43,6 +43,11 @@ #define SP0256_ROM_SIZE 2048 +/* Intonation on uSpeech changes SP0256 clock/oscillator frequency. + These values are based on a Kio's simulation and Thomas Busse tests. */ +#define SP0256_XTAL_NORMAL 3050000 +#define SP0256_XTAL_HIGH 3260000 + /* A 2 KiB memory chunk accessible by the Z80 when /ROMCS is low * (mirrored when active) */ static memory_page uspeech_memory_map_romcs[ MEMORY_PAGES_IN_2K ]; @@ -134,7 +139,7 @@ uspeech_port_intonation_normal( libspectrum_word port, libspectrum_byte data ) if( !uspeech_active ) return; /* Address 0x3000 can also be accessed via I/O (only write) */ - sp0256_set_intonation( 0 ); + sp0256_change_clock( SP0256_XTAL_NORMAL ); } static void @@ -143,7 +148,7 @@ uspeech_port_intonation_high( libspectrum_word port, libspectrum_byte data ) if( !uspeech_active ) return; /* Address 0x3001 can also be accessed via I/O (only write) */ - sp0256_set_intonation( 1 ); + sp0256_change_clock( SP0256_XTAL_HIGH ); } static void @@ -187,6 +192,8 @@ uspeech_init( void *context ) periph_register_paging_events( event_type_string, &page_event, &unpage_event ); + sp0256_set_clock( SP0256_XTAL_NORMAL ); + return 0; } @@ -293,6 +300,8 @@ uspeech_reset( int hard_reset GCC_UNUSED ) return; } + sp0256_set_clock( SP0256_XTAL_NORMAL ); + machine_current->ram.romcs = 0; uspeech_available = 1; @@ -354,11 +363,11 @@ uspeech_write( libspectrum_word address, libspectrum_byte b ) break; case 0x3000: /* This address is mirrored at 0011XXXX XXXXXXX0 */ - sp0256_set_intonation( 0 ); + sp0256_change_clock( SP0256_XTAL_NORMAL ); break; case 0x3001: /* This address is mirrored at 0011XXXX XXXXXXX1 */ - sp0256_set_intonation( 1 ); + sp0256_change_clock( SP0256_XTAL_HIGH ); break; } } |