Exemple #1
0
static int
sound_init_blip( Blip_Buffer **buf, Blip_Synth **synth )
{
  *buf = new_Blip_Buffer();
  blip_buffer_set_clock_rate( *buf, sound_get_effective_processor_speed() );
  /* Allow up to 1s of playback buffer - this allows us to cope with slowing
     down to 2% of speed where a single Speccy frame generates just under 1s
     of sound */
  if ( blip_buffer_set_sample_rate( *buf, settings_current.sound_freq, 1000 ) ) {
    sound_end();
    ui_error( UI_ERROR_ERROR, "out of memory at %s:%d", __FILE__, __LINE__ );
    return 0;
  }

  *synth = new_Blip_Synth();

  blip_synth_set_volume( *synth, sound_get_volume( settings_current.volume_beeper ) );
  blip_synth_set_output( *synth, *buf );

  blip_buffer_set_bass_freq( *buf, speaker_type[ option_enumerate_sound_speaker_type() ].bass );
  blip_synth_set_treble_eq( *synth, speaker_type[ option_enumerate_sound_speaker_type() ].treble );

  return 1;
}
Exemple #2
0
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 =
    (blip_sample_t *)libspectrum_calloc( sound_framesiz * sound_channels,
                                         sizeof(blip_sample_t) );
  /* initialize movie settings... */
  movie_init_sound( settings_current.sound_freq, sound_stereo_ay );

}
Exemple #3
0
int
sound_lowlevel_init( const char *device, int *freqptr, int *stereoptr )
{
  unsigned int exact_rate, periods;
  unsigned int val, n;
  snd_pcm_hw_params_t *hw_params;
  snd_pcm_sw_params_t *sw_params;
  snd_pcm_uframes_t avail_min = 0, sound_periodsize, bsize = 0;
  static int first_init = 1;
  static int init_running = 0;
  const char *option;
  char tmp;
  int err, dir, nperiods = NUM_FRAMES;

  float hz;

  if( init_running )
    return 0;
  
  init_running = 1;
/* select a default device if we weren't explicitly given one */

  option = device;
  while( option && *option ) {
    tmp = '*';
    if( ( err = sscanf( option, " buffer=%i %n%c", &val, &n, &tmp ) > 0 ) &&
		( tmp == ',' || strlen( option ) == n ) ) {
      if( val < 1 ) {
	fprintf( stderr, "Bad value for ALSA buffer size %i, using default\n",
		    val );
      } else {
        bsize = val;
      }
    } else if( ( err = sscanf( option, " frames=%i %n%c", &val, &n, &tmp ) > 0 ) &&
		( tmp == ',' || strlen( option ) == n ) ) {
      if( val < 1 ) {
	fprintf( stderr, "Bad value for ALSA buffer size %i frames, using default (%d)\n",
		    val, NUM_FRAMES );
      } else {
        nperiods = val;
      }
    } else if( ( err = sscanf( option, " avail=%i %n%c", &val, &n, &tmp ) > 0 ) &&
		( tmp == ',' || strlen( option ) == n ) ) {
      if( val < 1 ) {
	fprintf( stderr, "Bad value for ALSA avail_min size %i frames, using default\n",
		    val );
      } else {
        avail_min = val;
      }
    } else if( ( err = sscanf( option, " verbose %n%c", &n, &tmp ) == 1 ) &&
		( tmp == ','  || strlen( option ) == n ) ) {
      verb = 1;
    } else {					/* try as device name */
	while( isspace(*option) )
          option++;
	if( *option == '\'' )		/* force device... */
	  option++;
	pcm_name = option;
	n = strlen( pcm_name );
    }
    option += n + ( tmp == ',' );
  }

/* Open the sound device
 */
  if( pcm_name == NULL || *pcm_name == '\0' )
    pcm_name = "default";
  if( snd_pcm_open( &pcm_handle, pcm_name , stream, 0 ) < 0 ) {
    if( strcmp( pcm_name, "default" ) == 0 ) {
    /* we try a last one: plughw:0,0 but what a weired ALSA conf.... */
      if( snd_pcm_open( &pcm_handle, "plughw:0,0", stream, 0 ) < 0 ) {
        settings_current.sound = 0;
        ui_error( UI_ERROR_ERROR,
                  "couldn't open sound device 'default' and 'plughw:0,0' check ALSA configuration."
                  );
	init_running = 0;
        return 1;
      } else {
        if( first_init )
          fprintf( stderr,
                    "Couldn't open sound device 'default', using 'plughw:0,0' check ALSA configuration.\n"
                    );
      }
    }
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't open sound device '%s'.", pcm_name );
    init_running = 0;
    return 1;
  }

/* Allocate the snd_pcm_hw_params_t structure on the stack. */
  snd_pcm_hw_params_alloca( &hw_params );

/* Init hw_params with full configuration space */
  if( snd_pcm_hw_params_any( pcm_handle, hw_params ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR,
              "couldn't get configuration space on sound device '%s'.",
              pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( snd_pcm_hw_params_set_access( pcm_handle, hw_params,
                                    SND_PCM_ACCESS_RW_INTERLEAVED ) < 0) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set access interleaved on '%s'.",
              pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }
  
    /* Set sample format */
  if( snd_pcm_hw_params_set_format( pcm_handle, hw_params, 
#if defined WORDS_BIGENDIAN
				    SND_PCM_FORMAT_S16_BE
#else
				    SND_PCM_FORMAT_S16_LE
#endif
						    ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set format on '%s'.", pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  ch = *stereoptr ? 2 : 1;

  if( snd_pcm_hw_params_set_channels( pcm_handle, hw_params, ch )
	    < 0 ) {
    fprintf( stderr, "Couldn't set %s to '%s'.\n", pcm_name,
    		    (*stereoptr ? "stereo" : "mono") );
    ch = *stereoptr ? 1 : 2;		/* try with opposite */
    if( snd_pcm_hw_params_set_channels( pcm_handle, hw_params, ch )
	    < 0 ) {
      ui_error( UI_ERROR_ERROR, "couldn't set %s to '%s'.", pcm_name,
    		    (*stereoptr ? "stereo" : "mono") );
      settings_current.sound = 0;
      snd_pcm_close( pcm_handle );
      init_running = 0;
      return 1;
    }
    *stereoptr = *stereoptr ? 0 : 1;		/* write back */
  }

  framesize = ch << 1;			/* we always use 16 bit sorry :-( */
/* Set sample rate. If the exact rate is not supported */
/* by the hardware, use nearest possible rate.         */ 
  exact_rate = *freqptr;
  if( snd_pcm_hw_params_set_rate_near( pcm_handle, hw_params, &exact_rate,
							NULL ) < 0) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set rate %d on '%s'.",
						*freqptr, pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }
  if( first_init && *freqptr != exact_rate ) {
    fprintf( stderr, 
              "The rate %d Hz is not supported by your hardware. "
              "Using %d Hz instead.\n", *freqptr, exact_rate );
    *freqptr = exact_rate;
  }

  if( bsize != 0 ) {
    exact_periodsize = sound_periodsize = bsize / nperiods;
    if( bsize < 1 ) {
      fprintf( stderr,
                "bad value for ALSA buffer size %i, using default.\n",
		val );
      bsize = 0;
    }
  }

  if( bsize == 0 ) {
    /* 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;
    /* Amount of audio data we will accumulate before yielding back to the OS.
       Not much point having more than 100Hz playback, we probably get
       downgraded by the OS as being a hog too (unlimited Hz limits playback
       speed to about 2000% on my Mac, 100Hz allows up to 5000% for me) */
    if( hz > 100.0 ) hz = 100.0;
    exact_periodsize = sound_periodsize = *freqptr / hz;
  }

  dir = -1;
  if( snd_pcm_hw_params_set_period_size_near( pcm_handle, hw_params,
					    &exact_periodsize, &dir ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set period size %d on '%s'.",
                              (int)sound_periodsize, pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( first_init && ( exact_periodsize < sound_periodsize / 1.5 ||
		      exact_periodsize > sound_periodsize * 1.5    ) ) {
    fprintf( stderr,
              "The period size %d is not supported by your hardware. "
              "Using %d instead.\n", (int)sound_periodsize,
              (int)exact_periodsize );
  }

  periods = nperiods;
/* Set number of periods. Periods used to be called fragments. */
  if( snd_pcm_hw_params_set_periods_near( pcm_handle, hw_params, &periods,
                                          NULL ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set periods on '%s'.", pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( first_init && periods != nperiods ) {
    fprintf( stderr, "%d periods is not supported by your hardware. "
                    	     "Using %d instead.\n", nperiods, periods );
  }

  snd_pcm_hw_params_get_buffer_size( hw_params, &exact_bsize );

  /* Apply HW parameter settings to */
  /* PCM device and prepare device  */

  if( snd_pcm_hw_params( pcm_handle, hw_params ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR,"couldn't set hw_params on %s", pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  snd_pcm_sw_params_alloca( &sw_params );
  if( ( err = snd_pcm_sw_params_current( pcm_handle, sw_params ) ) < 0 ) {
    ui_error( UI_ERROR_ERROR,"couldn't get sw_params from %s: %s", pcm_name,
              snd_strerror ( err ) );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( ( err = snd_pcm_sw_params_set_start_threshold( pcm_handle,
		     sw_params, exact_periodsize * ( nperiods - 1 ) ) ) < 0 ) {
    ui_error( UI_ERROR_ERROR,"couldn't set start_treshold on %s: %s", pcm_name,
              snd_strerror ( err ) );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( !avail_min )
    avail_min = exact_periodsize >> 1;
  if( snd_pcm_sw_params_set_avail_min( pcm_handle,
		    sw_params, avail_min ) < 0 ) {
#if SND_LIB_VERSION < 0x10010
    if( ( err = snd_pcm_sw_params_set_sleep_min( pcm_handle,
    		    sw_params, 1 ) ) < 0 ) {
	fprintf( stderr, "Unable to set minimal sleep 1 for %s: %s\n", pcm_name,
              snd_strerror ( err ) );
    }
#else
    fprintf( stderr, "Unable to set avail min %s: %s\n", pcm_name,
    	     snd_strerror( err ) );
#endif
  }

#if SND_LIB_VERSION < 0x10010
  if( ( err = snd_pcm_sw_params_set_xfer_align( pcm_handle, sw_params, 1 ) ) < 0 ) {
    ui_error( UI_ERROR_ERROR,"couldn't set xfer_allign on %s: %s", pcm_name,
              snd_strerror ( err ) );
    init_running = 0;
    return 1;
  }
#endif
  
  if( ( err = snd_pcm_sw_params( pcm_handle, sw_params ) ) < 0 ) {
    ui_error( UI_ERROR_ERROR,"couldn't set sw_params on %s: %s", pcm_name,
              snd_strerror ( err ) );
    init_running = 0;
    return 1;
  }

  if( first_init ) snd_output_stdio_attach(&output, stdout, 0);

  first_init = 0;
  init_running = 0;
  return 0;	/* success */
}
Exemple #4
0
void
sound_init( const char *device )
{
  int ret;
  float hz;

  /* 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;

  sound_stereo_ay = settings_current.stereo_ay;

  /* only try for stereo if we need it */
  if( sound_stereo_ay )
    sound_stereo = 1;

  ret =
    sound_lowlevel_init( device, &settings_current.sound_freq, &sound_stereo );

  if( ret )
    return;

  if( !sound_init_blip(&left_buf, &left_beeper_synth) ) return;
  if( sound_stereo && !sound_init_blip(&right_buf, &right_beeper_synth) ) return;

  ay_a_synth = new_Blip_Synth();
  blip_synth_set_volume( ay_a_synth, sound_get_volume( settings_current.volume_ay) );
  blip_synth_set_output( ay_a_synth, left_buf );
  blip_synth_set_treble_eq( ay_a_synth, speaker_type[ settings_current.speaker_type ].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, speaker_type[ settings_current.speaker_type ].treble );

  ay_c_synth = new_Blip_Synth();
  blip_synth_set_volume( ay_c_synth, sound_get_volume( settings_current.volume_ay) );
  blip_synth_set_output( ay_c_synth, left_buf );
  blip_synth_set_treble_eq( ay_c_synth, speaker_type[ settings_current.speaker_type ].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).
   */
  if( !sound_stereo ) {
    sound_stereo_ay = 0;
  }

  ay_a_synth_r = NULL;
  ay_b_synth_r = NULL;
  ay_c_synth_r = NULL;

  if( sound_stereo ) {
    ay_c_synth_r = new_Blip_Synth();
    blip_synth_set_volume( ay_c_synth_r, sound_get_volume( settings_current.volume_ay ) );
    blip_synth_set_output( ay_c_synth_r, right_buf );

    if( sound_stereo_ay ) {
      /* stereo with ACB stereo. */
      blip_synth_set_output( ay_b_synth, right_buf );
    } else {
      ay_a_synth_r = new_Blip_Synth();
      blip_synth_set_volume( ay_a_synth_r, sound_get_volume( settings_current.volume_ay ) );
      blip_synth_set_output( ay_a_synth_r, right_buf );
      blip_synth_set_treble_eq( ay_a_synth_r, speaker_type[ settings_current.speaker_type ].treble );

      blip_synth_set_output( ay_b_synth, left_buf );

      ay_b_synth_r = new_Blip_Synth();
      blip_synth_set_volume( ay_b_synth_r, sound_get_volume( settings_current.volume_ay ) );
      blip_synth_set_output( ay_b_synth_r, right_buf );
      blip_synth_set_treble_eq( ay_b_synth_r, speaker_type[ settings_current.speaker_type ].treble );
    }
  } else {
    blip_synth_set_output( ay_b_synth, left_buf );
  }

  sound_enabled = sound_enabled_ever = 1;

  sound_channels = ( sound_stereo ? 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 = (blip_sample_t *)calloc( sound_framesiz * sound_channels,
                                     sizeof(blip_sample_t) );
}