Пример #1
0
SoundFile* load_sound_file(const std::string& filename)
{
    if(filename.length() > 6
            && filename.compare(filename.length()-6, 6, ".music") == 0) {
        return load_music_file(filename);
    }

    PHYSFS_file* file = PHYSFS_openRead(filename.c_str());
    if(!file) {
        std::stringstream msg;
        msg << "Couldn't open '" << filename << "': " << PHYSFS_getLastError() << ", using dummy sound file.";
        throw SoundError(msg.str());
    }

    try {
        char magic[4];
        if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
            throw SoundError("Couldn't read magic, file too short");
        PHYSFS_seek(file, 0);
        if(strncmp(magic, "RIFF", 4) == 0)
            return new WavSoundFile(file);
        else if(strncmp(magic, "OggS", 4) == 0)
            return new OggSoundFile(file, 0, -1);
        else
            throw SoundError("Unknown file format");
    } catch(std::exception& e) {
        std::stringstream msg;
        msg << "Couldn't read '" << filename << "': " << e.what();
        throw SoundError(msg.str());
    }
}
Пример #2
0
SoundFile* load_music_file(const std::string& filename)
{
    lisp::Parser parser(false);
    const lisp::Lisp* root = parser.parse(filename);
    const lisp::Lisp* music = root->get_lisp("supertux-music");
    if(music == NULL)
        throw SoundError("file is not a supertux-music file.");

    std::string raw_music_file;
    float loop_begin = 0;
    float loop_at    = -1;

    music->get("file", raw_music_file);
    music->get("loop-begin", loop_begin);
    music->get("loop-at", loop_at);

    if(loop_begin < 0) {
        throw SoundError("can't loop from negative value");
    }

    std::string basedir = FileSystem::dirname(filename);
    raw_music_file = FileSystem::normalize(basedir + raw_music_file);

    PHYSFS_file* file = PHYSFS_openRead(raw_music_file.c_str());
    if(!file) {
        std::stringstream msg;
        msg << "Couldn't open '" << raw_music_file << "': " << PHYSFS_getLastError();
        throw SoundError(msg.str());
    }

    return new OggSoundFile(file, loop_begin, loop_at);
}
size_t
WavSoundFile::read(void* buffer, size_t buffer_size)
{
  PHYSFS_sint64 end = datastart + size;
  PHYSFS_sint64 cur = PHYSFS_tell(file);
  if(cur >= end)
    return 0;

  size_t readsize = std::min(static_cast<size_t> (end - cur), buffer_size);
  if(PHYSFS_read(file, buffer, readsize, 1) != 1)
    throw SoundError("read error while reading samples");

#ifdef WORDS_BIGENDIAN
  if (bits_per_sample != 16)
    return readsize;
  char *tmp = (char*)buffer;

  size_t i;
  char c;
  for (i = 0; i < readsize / 2; i++)
  {
    c          = tmp[2*i];
    tmp[2*i]   = tmp[2*i+1];
    tmp[2*i+1] = c;
  }

  buffer = tmp;
#endif

  return readsize;
}
static inline uint16_t read16LE(PHYSFS_file* file)
{
  uint16_t result;
  if(PHYSFS_readULE16(file, &result) == 0)
    throw SoundError("file too short");

  return result;
}
WavSoundFile::WavSoundFile(PHYSFS_file* file_) :
  file(file_),
  datastart()
{
  assert(file);
  char magic[4];
  if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
    throw SoundError("Couldn't read file magic (not a wave file)");
  if(strncmp(magic, "RIFF", 4) != 0) {
    log_debug << "MAGIC: " << magic << std::endl;
    throw SoundError("file is not a RIFF wav file");
  }

  uint32_t wavelen = read32LE(file);
  (void) wavelen;

  if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
    throw SoundError("Couldn't read chunk header (not a wav file?)");
  if(strncmp(magic, "WAVE", 4) != 0)
    throw SoundError("file is not a valid RIFF/WAVE file");

  char chunkmagic[4];
  uint32_t chunklen;

  // search audio data format chunk
  do {
    if(PHYSFS_read(file, chunkmagic, sizeof(chunkmagic), 1) != 1)
      throw SoundError("EOF while searching format chunk");
    chunklen = read32LE(file);

    if(strncmp(chunkmagic, "fmt ", 4) == 0)
      break;

    if(strncmp(chunkmagic, "fact", 4) == 0
       || strncmp(chunkmagic, "LIST", 4) == 0) {
      // skip chunk
      if(PHYSFS_seek(file, PHYSFS_tell(file) + chunklen) == 0)
        throw SoundError("EOF while searching fmt chunk");
    } else {
      throw SoundError("complex WAVE files not supported");
    }
  } while(true);

  if(chunklen < 16)
    throw SoundError("Format chunk too short");

  // parse format
  uint16_t encoding = read16LE(file);
  if(encoding != 1)
    throw SoundError("only PCM encoding supported");
  channels = read16LE(file);
  rate = read32LE(file);
  uint32_t byterate = read32LE(file);
  (void) byterate;
  uint16_t blockalign = read16LE(file);
  (void) blockalign;
  bits_per_sample = read16LE(file);

  if(chunklen > 16) {
    if(PHYSFS_seek(file, PHYSFS_tell(file) + (chunklen-16)) == 0)
      throw SoundError("EOF while reading rest of format chunk");
  }

  // set file offset to DATA chunk data
  do {
    if(PHYSFS_read(file, chunkmagic, sizeof(chunkmagic), 1) != 1)
      throw SoundError("EOF while searching data chunk");
    chunklen = read32LE(file);

    if(strncmp(chunkmagic, "data", 4) == 0)
      break;

    // skip chunk
    if(PHYSFS_seek(file, PHYSFS_tell(file) + chunklen) == 0)
      throw SoundError("EOF while searching fmt chunk");
  } while(true);

  datastart = PHYSFS_tell(file);
  size = static_cast<size_t> (chunklen);
}
void
WavSoundFile::reset()
{
  if(PHYSFS_seek(file, datastart) == 0)
    throw SoundError("Couldn't seek to data start");
}
Пример #7
0
void GameEnvironment::initSound()  throw(Exception)
{
	triggerMonsterSounds = true;
	footstepSoundPlayed = false;
	sprintStepEnable = false;

	beepCounter = 0;
	delayBeep = 100;

	enemyMonsterRandomSoundId = 0;
	enemyMonsterRandomSoundFlag = 0;
	enemyMonsterRandomSoundCounter = 0;

	sound = new FMOD::Sound*[15]; 
	channel = new FMOD::Channel*[15];

	if (FMOD::System_Create(&system) != FMOD_OK)
		throw InitFmodError("Create the main object of fmod failed!\nPlease press OK and restart game.");
	if (system->init(10, FMOD_INIT_NORMAL, NULL) != FMOD_OK)
		throw InitFmodError("Initialization fmod failed!\nPlease press OK and restart game.");
	if (system->createSound("data/audio/monster/attack/alien_attack_ls.wav", FMOD_LOOP_OFF, 0, &sound[0]) != FMOD_OK) // zmiana z &sound
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/attack/alien_attack_ls.wav");
	if (system->createSound("data/audio/footstep.wav", FMOD_LOOP_NORMAL, 0, &sound[1]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/footstep.wav");
	if (system->createSound("data/audio/footstep_run.wav", FMOD_LOOP_NORMAL, 0, &sound[2]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/footstep_run.wav");
	if (system->createSound("data/audio/ambient.wav", FMOD_LOOP_NORMAL, 0, &sound[3]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/ambient.wav");
	if (system->createSound("data/audio/monster/attack/alien_attack_hs.wav", FMOD_LOOP_OFF, 0, &sound[4]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/attack/alien_attack_hs.wav");

	if (system->createSound("data/audio/monster/random/alien_sounds_random_1.wav", FMOD_LOOP_OFF, 0, &sound[5]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/random/alien_sounds_random_1.wav");
	if (system->createSound("data/audio/monster/random/alien_sounds_random_2.wav", FMOD_LOOP_OFF, 0, &sound[6]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/random/alien_sounds_random_2.wav");
	if (system->createSound("data/audio/monster/random/alien_sounds_random_3.wav", FMOD_LOOP_OFF, 0, &sound[7]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/random/alien_sounds_random_3.wav");
	if (system->createSound("data/audio/monster/random/alien_sounds_random_4.wav", FMOD_LOOP_OFF, 0, &sound[8]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/random/alien_sounds_random_4.wav");
	if (system->createSound("data/audio/monster/random/alien_sounds_random_5.wav", FMOD_LOOP_OFF, 0, &sound[9]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/random/alien_sounds_random_5.wav");
	if (system->createSound("data/audio/monster/random/alien_sounds_random_6.wav", FMOD_LOOP_OFF, 0, &sound[10]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/random/alien_sounds_random_6.wav");
	if (system->createSound("data/audio/monster/random/alien_sounds_random_7.wav", FMOD_LOOP_OFF, 0, &sound[11]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/random/alien_sounds_random_7.wav");
	if (system->createSound("data/audio/monster/random/alien_sounds_random_8.wav", FMOD_LOOP_OFF, 0, &sound[12]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/random/alien_sounds_random_8.wav");
	if (system->createSound("data/audio/monster/random/alien_sounds_random_9.wav", FMOD_LOOP_OFF, 0, &sound[13]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/random/alien_sounds_random_9.wav");
	if (system->createSound("data/audio/monster/footstep/alien_footstep_echo.wav", FMOD_LOOP_NORMAL, 0, &sound[14]) != FMOD_OK)
		throw SoundError("Failed to create sound!\nPlease press OK and restart game.\nExpected path of file:\ndata/audio/monster/footstep/alien_footstep_echo.wav");
	else
		system->playSound(sound[3], NULL, false, &channel[3]);
}
Пример #8
0
HRESULT Sound_VBL()
{
#if SCREENS_PER_SOUND_VBL != 1
  static int screens_countdown=SCREENS_PER_SOUND_VBL;
  screens_countdown--;if (screens_countdown>0) return DD_OK;
  screens_countdown=SCREENS_PER_SOUND_VBL;
  cpu_time_of_last_sound_vbl=ABSOLUTE_CPU_TIME;
#endif
  if (sound_internal_speaker){
    static double op=0;
    int abc,chan=-1,max_vol=0,vol;

    // Find loudest channel
    for (abc=0;abc<3;abc++){
      if ((psg_reg[PSGR_MIXER] & (1 << abc))==0){ // Channel enabled in mixer
        vol=(psg_reg[PSGR_AMPLITUDE_A+abc] & 15);
        if (vol>max_vol){
          chan=abc;
          max_vol=vol;
        }
      }
    }
    if (chan==-1){ //no sound
      internal_speaker_sound_by_period(0);
      op=0;
    }else{
      double p=((((int)psg_reg[chan*2+1] & 0xf) << 8) + psg_reg[chan*2]);
      p*=(1193181.0/125000.0);
      if (op!=p){
        op=p;
        internal_speaker_sound_by_period((int)p);
      }
    }
  }

  if (psg_capture_file){
    psg_capture_check_boundary();
  }

  // This just clears up some clicks when Sound_VBL is called very soon after Sound_Start
  if (sound_first_vbl){
    sound_first_vbl=0;
    return DS_OK;
  }

  if (sound_mode==SOUND_MODE_MUTE) return DS_OK;
  if (UseSound==0) return DSERR_GENERIC;  // Not initialised
  if (SoundActive()==0) return DS_OK;        // Not started

  log("");
  log("SOUND: Start of Sound_VBL");

  void *DatAdr[2]={NULL,NULL};
  DWORD LockLength[2]={0,0};
  DWORD s_time,write_time_1,write_time_2;
  HRESULT Ret;

  int *source_p;

  DWORD n_samples_per_vbl=(sound_freq*SCREENS_PER_SOUND_VBL)/shifter_freq;

  log(EasyStr("SOUND: Calculating time; psg_time_of_start_of_buffer=")+psg_time_of_start_of_buffer);


  s_time=SoundGetTime();
  //we have data from time_of_last_vbl+PSG_WRITE_N_SCREENS_AHEAD*n_samples_per_vbl up to
  //wherever we want

  write_time_1=psg_time_of_last_vbl_for_writing; //3 screens ahead of where the cursor was
//  write_time_1=max(write_time_1,min_write_time); //minimum time for new write

  write_time_2=max(write_time_1+(n_samples_per_vbl+PSG_WRITE_EXTRA),
                   s_time+(n_samples_per_vbl+PSG_WRITE_EXTRA));
  if ((write_time_2-write_time_1)>PSG_CHANNEL_BUF_LENGTH){
    write_time_2=write_time_1+PSG_CHANNEL_BUF_LENGTH;
  }

//  psg_last_write_time=write_time_2;

  DWORD time_of_next_vbl_to_write=max(s_time+n_samples_per_vbl*psg_write_n_screens_ahead,psg_time_of_next_vbl_for_writing);
  if (time_of_next_vbl_to_write>s_time+n_samples_per_vbl*(psg_write_n_screens_ahead+2)){  //
    time_of_next_vbl_to_write=s_time+n_samples_per_vbl*(psg_write_n_screens_ahead+2);     // new bit added by Ant 9/1/2001 to stop the sound lagging behind
  }                                                                                    // get rid of it if it is causing problems

  log(EasyStr("   writing from ")+write_time_1+" to "+write_time_2+"; current play cursor at "+s_time+" ("+play_cursor+"); minimum write at "+min_write_time+" ("+write_cursor+")");

//  log_write(EasyStr("writing ")+(write_time_1-s_time)+" samples ahead of play cursor, "+(write_time_1-min_write_time)+" ahead of min write");

#ifdef SHOW_WAVEFORM
  temp_waveform_display_counter=write_time_1 MOD_PSG_BUF_LENGTH;
  temp_waveform_play_counter=play_cursor;
#endif
  log("SOUND: Working out data up to the end of this VBL plus a bit more for all channels");
  for (int abc=2;abc>=0;abc--){
    psg_write_buffer(abc,time_of_next_vbl_to_write+PSG_WRITE_EXTRA);
  }
  if (dma_sound_on_this_screen){
    WORD w[2]={dma_sound_channel_buf[dma_sound_channel_buf_last_write_t-2],dma_sound_channel_buf[dma_sound_channel_buf_last_write_t-1]};
    for (int i=0;i<PSG_WRITE_EXTRA;i++){
      if (dma_sound_channel_buf_last_write_t>=DMA_SOUND_BUFFER_LENGTH) break;
      dma_sound_channel_buf[dma_sound_channel_buf_last_write_t++]=w[0];
      dma_sound_channel_buf[dma_sound_channel_buf_last_write_t++]=w[1];
    }
  }else{
    WORD w1,w2;
    dma_sound_get_last_sample(&w1,&w2);
    dma_sound_channel_buf[0]=w1;
    dma_sound_channel_buf[1]=w2;
    dma_sound_channel_buf_last_write_t=0;
  }

  // write_time_1 and 2 are sample variables, convert to bytes
  DWORD StartByte=(write_time_1 MOD_PSG_BUF_LENGTH)*sound_bytes_per_sample;
  DWORD NumBytes=((write_time_2-write_time_1)+1)*sound_bytes_per_sample;
  log(EasyStr("SOUND: Trying to lock from ")+StartByte+", length "+NumBytes);
  Ret=SoundLockBuffer(StartByte,NumBytes,&DatAdr[0],&LockLength[0],&DatAdr[1],&LockLength[1]);
  if (Ret!=DSERR_BUFFERLOST){
    if (Ret!=DS_OK){
      log_write("SOUND: Lock totally failed, disaster!");
      return SoundError("Lock for PSG Buffer Failed",Ret);
    }
    log(EasyStr("SOUND: Locked lengths ")+LockLength[0]+", "+LockLength[1]);
    int i=min(max(int(write_time_1-psg_time_of_last_vbl_for_writing),0),PSG_CHANNEL_BUF_LENGTH-10);
    int v=psg_voltage,dv=psg_dv; //restore from last time
    log(EasyStr("SOUND: Zeroing channels buffer up to ")+i);
    for (int j=0;j<i;j++){
      psg_channels_buf[j]=VOLTAGE_FP(VOLTAGE_ZERO_LEVEL); //zero the start of the buffer
    }
    source_p=psg_channels_buf+i;
    int samples_left_in_buffer=max(PSG_CHANNEL_BUF_LENGTH-i,0);
    int countdown_to_storing_values=max((int)(time_of_next_vbl_to_write-write_time_1),0);
    //this is set when we are counting down to the start time of the next write
    bool store_values=false,chipmode=bool((sound_mode==SOUND_MODE_EMULATED) ? false:true);
    if (sound_mode==SOUND_MODE_SHARPSAMPLES) chipmode=(psg_reg[PSGR_MIXER] & b00111111)!=b00111111;
    if (sound_mode==SOUND_MODE_SHARPCHIP)    chipmode=(psg_reg[PSGR_MIXER] & b00111111)==b00111111;
    if (sound_record){
      sound_record_to_wav(countdown_to_storing_values,write_time_1,chipmode,source_p);
    }

#ifdef WRITE_ONLY_SINE_WAVE
    DWORD t=write_time_1;
#endif

    int val;
    log("SOUND: Starting to write to buffers");
    WORD *lp_dma_sound_channel=dma_sound_channel_buf;
    WORD *lp_max_dma_sound_channel=dma_sound_channel_buf+dma_sound_channel_buf_last_write_t;
    BYTE *pb;
    WORD *pw;
    for (int n=0;n<2;n++){
      if (DatAdr[n]){
        pb=(BYTE*)(DatAdr[n]);
        pw=(WORD*)(DatAdr[n]);
        int c=min(int(LockLength[n]/sound_bytes_per_sample),samples_left_in_buffer),oc=c;
        if (c>countdown_to_storing_values){
          c=countdown_to_storing_values;
          oc-=countdown_to_storing_values;
          store_values=true;
        }
        for (;;){
          if (sound_num_bits==8){
            if (chipmode){
              if (sound_low_quality==0){
                WRITE_SOUND_LOOP(CALC_V_CHIP,pb,BYTE,DWORD_B_1);
              }else{
                WRITE_SOUND_LOOP(CALC_V_CHIP_25KHZ,pb,BYTE,DWORD_B_1);
              }
            }else{
              WRITE_SOUND_LOOP(CALC_V_EMU,pb,BYTE,DWORD_B_1);
            }
          }else{
            if (chipmode){
              if (sound_low_quality==0){
                WRITE_SOUND_LOOP(CALC_V_CHIP,pw,WORD,MSB_W ^ DWORD_W_0);
              }else{
                WRITE_SOUND_LOOP(CALC_V_CHIP_25KHZ,pw,WORD,MSB_W ^ DWORD_W_0);
              }
            }else{
              WRITE_SOUND_LOOP(CALC_V_EMU,pw,WORD,MSB_W ^ DWORD_W_0);
            }
          }

          if (store_values){
            c=oc;
            psg_voltage=v;
            psg_dv=dv;
            store_values=false;
            countdown_to_storing_values=0x7fffffff; //don't store the values again.
          }else{
            countdown_to_storing_values-=LockLength[n]/sound_bytes_per_sample;
            break;
          }
        }
        samples_left_in_buffer-=LockLength[n]/sound_bytes_per_sample;
      }
    }
    SoundUnlock(DatAdr[0],LockLength[0],DatAdr[1],LockLength[1]);
    while (source_p < (psg_channels_buf+PSG_CHANNEL_BUF_LENGTH)){
      *(source_p++)=VOLTAGE_FP(VOLTAGE_ZERO_LEVEL); //zero the rest of the buffer
    }
  }

  psg_buf_pointer[0]=0;
  psg_buf_pointer[1]=0;
  psg_buf_pointer[2]=0;

  psg_time_of_last_vbl_for_writing=time_of_next_vbl_to_write;

  psg_time_of_next_vbl_for_writing=max(s_time+n_samples_per_vbl*(psg_write_n_screens_ahead+1),
                                       time_of_next_vbl_to_write+n_samples_per_vbl);
  psg_time_of_next_vbl_for_writing=min(psg_time_of_next_vbl_for_writing,
                                       s_time+(PSG_BUF_LENGTH/2));
  log(EasyStr("SOUND: psg_time_of_next_vbl_for_writing=")+psg_time_of_next_vbl_for_writing);

  psg_n_samples_this_vbl=psg_time_of_next_vbl_for_writing-psg_time_of_last_vbl_for_writing;

  log("SOUND: End of Sound_VBL");
  log("");

  return DS_OK;
}