libspectrum_error libspectrum_wav_read( libspectrum_tape *tape, const char *filename ) { libspectrum_byte *buffer; size_t length; libspectrum_byte *tape_buffer; size_t tape_length; size_t data_length; libspectrum_tape_block *block = NULL; int frames; /* Our filehandle from libaudiofile */ AFfilehandle handle; /* The track we're using in the file */ int track = AF_DEFAULT_TRACK; if( !filename ) { libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "libspectrum_wav_read: no filename provided - wav files can only be loaded from a file" ); return LIBSPECTRUM_ERROR_LOGIC; } handle = afOpenFile( filename, "r", NULL ); if( handle == AF_NULL_FILEHANDLE ) { libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "libspectrum_wav_read: audiofile failed to open file:%s", filename ); return LIBSPECTRUM_ERROR_LOGIC; } if( afSetVirtualSampleFormat( handle, track, AF_SAMPFMT_UNSIGNED, 8 ) ) { afCloseFile( handle ); libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "libspectrum_wav_read: audiofile failed to set virtual sample format" ); return LIBSPECTRUM_ERROR_LOGIC; } if( afSetVirtualChannels( handle, track, 1 ) ) { afCloseFile( handle ); libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "libspectrum_wav_read: audiofile failed to set virtual channel count" ); return LIBSPECTRUM_ERROR_LOGIC; } length = afGetFrameCount( handle, track ); tape_length = length; if( tape_length%8 ) tape_length += 8 - (tape_length%8); buffer = libspectrum_new0( libspectrum_byte, tape_length * afGetChannels(handle, track) ); frames = afReadFrames( handle, track, buffer, length ); if( frames == -1 ) { libspectrum_free( buffer ); afCloseFile( handle ); libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "libspectrum_wav_read: can't calculate number of frames in audio file" ); return LIBSPECTRUM_ERROR_CORRUPT; } if( !length ) { libspectrum_free( buffer ); afCloseFile( handle ); libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "libspectrum_wav_read: empty audio file, nothing to load" ); return LIBSPECTRUM_ERROR_CORRUPT; } if( frames != length ) { libspectrum_free( buffer ); afCloseFile( handle ); libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT, "libspectrum_wav_read: read %d frames, but expected %lu\n", frames, (unsigned long)length ); return LIBSPECTRUM_ERROR_CORRUPT; } block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RAW_DATA ); /* 44100 Hz 79 t-states 22050 Hz 158 t-states */ libspectrum_tape_block_set_bit_length( block, 3500000/afGetRate( handle, track ) ); libspectrum_set_pause_ms( block, 0 ); libspectrum_tape_block_set_bits_in_last_byte( block, length % LIBSPECTRUM_BITS_IN_BYTE ? length % LIBSPECTRUM_BITS_IN_BYTE : LIBSPECTRUM_BITS_IN_BYTE ); data_length = tape_length / LIBSPECTRUM_BITS_IN_BYTE; libspectrum_tape_block_set_data_length( block, data_length ); tape_buffer = libspectrum_new0( libspectrum_byte, data_length ); libspectrum_byte *from = buffer; libspectrum_byte *to = tape_buffer; length = tape_length; do { libspectrum_byte val = 0; int i; for( i = 7; i >= 0; i-- ) { if( *from++ > 127 ) val |= 1 << i; } *to++ = val; } while ((length -= 8) > 0); libspectrum_tape_block_set_data( block, tape_buffer ); libspectrum_tape_append_block( tape, block ); if( afCloseFile( handle ) ) { libspectrum_free( buffer ); libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, "libspectrum_wav_read: failed to close audio file" ); return LIBSPECTRUM_ERROR_UNKNOWN; } libspectrum_free( buffer ); /* Successful completion */ return LIBSPECTRUM_ERROR_NONE; }
void sound_init( const char *device ) { float hz; double treble; Blip_Synth **ay_left_synth; Blip_Synth **ay_mid_synth; Blip_Synth **ay_mid_synth_r; Blip_Synth **ay_right_synth; /* Allow sound as long as emulation speed is greater than 2% (less than that and a single Speccy frame generates more than a seconds worth of sound which is bigger than the maximum Blip_Buffer of 1 second) */ if( !( !sound_enabled && settings_current.sound && settings_current.emulation_speed > 1 ) ) return; /* only try for stereo if we need it */ sound_stereo_ay = option_enumerate_sound_stereo_ay(); if( settings_current.sound && sound_lowlevel_init( device, &settings_current.sound_freq, &sound_stereo_ay ) ) return; if( !sound_init_blip(&left_buf, &left_beeper_synth) ) return; if( sound_stereo_ay != SOUND_STEREO_AY_NONE && !sound_init_blip(&right_buf, &right_beeper_synth) ) return; treble = speaker_type[ option_enumerate_sound_speaker_type() ].treble; ay_a_synth = new_Blip_Synth(); blip_synth_set_volume( ay_a_synth, sound_get_volume( settings_current.volume_ay) ); blip_synth_set_treble_eq( ay_a_synth, treble ); ay_b_synth = new_Blip_Synth(); blip_synth_set_volume( ay_b_synth, sound_get_volume( settings_current.volume_ay) ); blip_synth_set_treble_eq( ay_b_synth, treble ); ay_c_synth = new_Blip_Synth(); blip_synth_set_volume( ay_c_synth, sound_get_volume( settings_current.volume_ay) ); blip_synth_set_treble_eq( ay_c_synth, treble ); left_specdrum_synth = new_Blip_Synth(); blip_synth_set_volume( left_specdrum_synth, sound_get_volume( settings_current.volume_specdrum ) ); blip_synth_set_output( left_specdrum_synth, left_buf ); blip_synth_set_treble_eq( left_specdrum_synth, treble ); /* important to override these settings if not using stereo * (it would probably be confusing to mess with the stereo * settings in settings_current though, which is why we make copies * rather than using the real ones). */ ay_a_synth_r = NULL; ay_b_synth_r = NULL; ay_c_synth_r = NULL; if( sound_stereo_ay != SOUND_STEREO_AY_NONE ) { /* Attach the Blip_Synth's we've already created as appropriate, and * create one more Blip_Synth for the middle channel's right buffer. */ if( sound_stereo_ay == SOUND_STEREO_AY_ACB ) { ay_left_synth = &ay_a_synth; ay_mid_synth = &ay_c_synth; ay_mid_synth_r = &ay_c_synth_r; ay_right_synth = &ay_b_synth; } else if ( sound_stereo_ay == SOUND_STEREO_AY_ABC ) { ay_left_synth = &ay_a_synth; ay_mid_synth = &ay_b_synth; ay_mid_synth_r = &ay_b_synth_r; ay_right_synth = &ay_c_synth; } else { ui_error( UI_ERROR_ERROR, "unknown AY stereo separation type: %d", sound_stereo_ay ); fuse_abort(); } blip_synth_set_output( *ay_left_synth, left_buf ); blip_synth_set_output( *ay_mid_synth, left_buf ); blip_synth_set_output( *ay_right_synth, right_buf ); *ay_mid_synth_r = new_Blip_Synth(); blip_synth_set_volume( *ay_mid_synth_r, sound_get_volume( settings_current.volume_ay ) ); blip_synth_set_output( *ay_mid_synth_r, right_buf ); blip_synth_set_treble_eq( *ay_mid_synth_r, treble ); right_specdrum_synth = new_Blip_Synth(); blip_synth_set_volume( right_specdrum_synth, sound_get_volume( settings_current.volume_specdrum ) ); blip_synth_set_output( right_specdrum_synth, right_buf ); blip_synth_set_treble_eq( right_specdrum_synth, treble ); } else { blip_synth_set_output( ay_a_synth, left_buf ); blip_synth_set_output( ay_b_synth, left_buf ); blip_synth_set_output( ay_c_synth, left_buf ); } sound_enabled = sound_enabled_ever = 1; sound_channels = ( sound_stereo_ay != SOUND_STEREO_AY_NONE ? 2 : 1 ); /* Adjust relative processor speed to deal with adjusting sound generation frequency against emulation speed (more flexible than adjusting generated sample rate) */ hz = ( float )sound_get_effective_processor_speed() / machine_current->timings.tstates_per_frame; /* Size of audio data we will get from running a single Spectrum frame */ sound_framesiz = ( float )settings_current.sound_freq / hz; sound_framesiz++; samples = libspectrum_new0( blip_sample_t, sound_framesiz * sound_channels ); /* initialize movie settings... */ movie_init_sound( settings_current.sound_freq, sound_stereo_ay ); }