Example #1
0
int main(int argc, char *argv[])
{
 int size;
 int curarg;
 uint8 *buf;

 Interface = SexyAL_Init(0);

 DriverTypes = Interface->EnumerateTypes(Interface);

 puts("\n*** Festalon v"FESTALON_VERSION);
 if(argc<=1) 
 {
  printf("\tUsage: %s [options] file1.nsf file2.nsf ... fileN.nsf\n\n",argv[0]);
  puts("\tExample Options:");
  puts("\t -rate 44100\t\tSet playback rate to 44100Hz(default: 48000Hz).");
  puts("\t -quality 1\t\tSet quality to 1, the highest(the lowestis 0; default: 0).");
  puts("\t -volume 200\t\tSet volume to 200%(default: 100%).");
  puts("\t -buffering 100\t\tSet desired buffering level to 100 milliseconds(default: 100).");
  puts("\t -lowpass 1\t\tTurn on lowpass filter(default: 0).");
  puts("\t -lowpasscorner 8000\tSet lowpass corner frequency(at which the response is about -3dB) to 8000Hz(default: 10000Hz).");
  puts("\t -lowpassorder 2\tSet lowpass filter order to 2(default: 2).");
  puts("\t -record filename.wav\tRecords audio in MS PCM format.  An existing file won't be overwritten.");
  puts("\t\t\t\tWhen playing multiple files, only the first opened file will have its music recorded.");
  puts("\t -ao x\t\t\tSelect output type/driver.  Valid choices are:");
  {
   int x = 0;
   while(DriverTypes[x].name)
   {
    printf("\t\t\t\t %s - %s",DriverTypes[x].short_name,DriverTypes[x].name);
    if(!x) printf("\t(*Default*)");
    puts("");
    x++;
   }
  }
  puts("\t -aodevice id\t\tSelect output device by id.  The default is \"NULL\", which opens the default/preferred device.");
  puts("\t\t\t\t Try \"-aodevice help\" to see the list of devices.");
  Interface->Destroy(Interface);
  return(-1);
 }

 curarg = ParseArguments(argc, argv, TODArgs);

 if(-1 == (CurDriverIndex = FindCurDriver(DriverTypes, Config.ao)))
  return(-1);

 if(Config.aodevice)
 {
  if(!strcmp(Config.aodevice,"help"))
  {
   SexyAL_enumdevice *devices = Interface->EnumerateDevices(Interface, DriverTypes[CurDriverIndex].type);

   if(!devices)
   {
    printf("\tNo predefined output devices are available with this driver type.\n");
    return(-1);
   }
   printf("\tOutput devices(ID, name) for \"%s\":\n",DriverTypes[CurDriverIndex].name);
   while(devices->next)
   {
    printf("\t %s, %s\n",devices->id,devices->name);
    devices = devices->next;
   }
   return(-1);
  }
 }

 if(Config.quality != 0 && Config.quality != 1)
  Config.quality = 0;

 tcgetattr(0,&oldtio);

 newtio=oldtio;
 newtio.c_lflag&=~(ICANON|ECHO);

 signal(SIGTERM,siggo);
 signal(SIGINT,siggo);

 tcsetattr(0,TCSANOW,&newtio);
 sa = fcntl(fileno(stdin), F_GETFL);
 fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);

 for(;curarg < argc && !eexit; curarg++)
 //while(argc-->1 && !eexit)
 {
  FILE *fp;
  printf("\nLoading %s... ",argv[curarg]);
  if(!(fp=fopen(argv[curarg],"rb"))) {printf("Error opening file: %s\n",strerror(errno));continue;}
  fseek(fp,0,SEEK_END);
  size=ftell(fp);
  fseek(fp,0,SEEK_SET);
  buf=malloc(size);
  fread(buf,1,size,fp); 
  fclose(fp);

  if(!(Player=FESTAI_Load(buf,size) ))
  {
   puts("Error loading file!");
   free(buf);
   continue;
  }
  free(buf);

  puts("");

  memset(&format, 0, sizeof(format));
  memset(&buffering, 0, sizeof(buffering));

  format.sampformat = SEXYAL_FMT_PCMFLOAT;
  format.channels = Player->OutChannels;
  format.rate = Config.rate;

  buffering.fragsizems = 10;     // Granularity.
  buffering.ms = Config.buffering;

  printf(" Using \"%s\" audio driver:",DriverTypes[CurDriverIndex].name);
  if(!(Output=Interface->Open(Interface,Config.aodevice,&format,&buffering, DriverTypes[CurDriverIndex].type)))
  {
   puts("Error opening sound device.");
   continue;
   //return(-1);
  }

  putchar('\n');

  printf("  Playback Rate:\t%dHz\n",format.rate);
  printf("  Output Channels:\t%d\n",format.channels);
  printf("  Output Format:\t");
  if(format.sampformat == SEXYAL_FMT_PCMFLOAT)
   puts("\t32-bit Floating Point");
  else
  {
   if(format.sampformat&0x1) printf("Signed, ");
   else printf("Unsigned, ");

   printf("%d bits\n",(format.sampformat >> 4) << 3);
  }
  printf("  Estimated Latency:\t%d ms\n",buffering.latency * 1000 / format.rate);

  FESTAI_SetSound(Player, format.rate, Config.quality);

  if(WRFilename)
  {
      if(!FCEUI_BeginWaveRecord(format.rate,Player->OutChannels,WRFilename))
      {
	  free(WRFilename);
	  WRFilename = 0;
      }
  }



  //printf("%d:%d\n",buffering.fragsize, buffering.fragcount);

  format.sampformat=SEXYAL_FMT_PCMFLOAT;
  format.channels=Player->OutChannels;
  format.byteorder=0;
 
  Output->SetConvert(Output,&format);

  Config.volume = FESTAI_SetVolume(Player, Config.volume);
  FESTAI_Disable(Player, disabled);

  poosh();
  puts("");
  ShowInfo();
  if(!FESTAI_SetLowpass(Player, Config.lowpass, Config.lowpasscorner, Config.lowpassorder))
  {
   puts(" Error activating lowpass filter!");
  }
  else if(Config.lowpass)
   printf(" Lowpass filter on.  Corner frequency: %dHz, Order: %d\n",Config.lowpasscorner,Config.lowpassorder);

 current=FESTAI_SongControl(Player,0,0);
 lastms = ~0;
 frames_written = 0;
 puts("\n\n");

 ShowStatus(1,1);

 //#define TICKEROO
 #ifdef TICKEROO
 static uint64 last_tick,total_ticks,total;
 total = 0;
 total_ticks = 0;
 #endif

 while(!eexit)
 {
  static char t[3]={0,0,0};
  int len;
  float *buf;

  ShowStatus(0,0);

  if(paused)
  {
   usleep(10);
  }
  else
  {
   #ifdef TICKEROO
   last_tick=getticks();
   #endif

   buf=FESTAI_Emulate(Player, &len);

   #ifdef TICKEROO
   total_ticks += getticks() - last_tick;
   total += len;
   #endif

   if(WRFilename)
       FCEU_WriteWaveData(buf, len);
   frames_written += len;
   Output->Write(Output,buf,len);

   #ifdef TICKEROO
   if(total >= 100000/2)
   {
    printf("%8f\n", (double)total*1000000/total_ticks);
    rmode();
    exit(1);
   }
   #endif
  }
  while(read(fileno(stdin),&t[0],1)>=0)
  {
    static char kcc[20] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
			  '!', '@', '#', '$', '%', '^', '&', '*', '(', ')'};
    int x;

    for(x=0; x<20; x++)
	if(kcc[x] == t[0])
	{
	 disabled^=1<<x;
	 FESTAI_Disable(Player,disabled);
         poosh();
	 ShowStatus(0,1);
	 break;
	}

    if(t[2]==27 && t[1]==91)
     switch(t[0])
     {
      case 65:current=FESTAI_SongControl(Player,10,0);poosh(); lastms = ~0;frames_written=0;ShowStatus(1,1);break;
      case 66:current=FESTAI_SongControl(Player,-10,0);poosh(); lastms = ~0;frames_written=0;ShowStatus(1,1);break;
      case 67:current=FESTAI_SongControl(Player,1,0);poosh(); lastms = ~0;frames_written=0;ShowStatus(1,1);break;
      case 68:current=FESTAI_SongControl(Player,-1,0);poosh(); lastms = ~0;frames_written=0;ShowStatus(1,1);break;
     }
    else
    switch(tolower(t[0]))
    {
     case 10: lastms = ~0;frames_written=0;poosh();current=FESTAI_SongControl(Player, 0,0);ShowStatus(1,1);break;
     case '`': poosh();break;

     case 'a': Config.volume-=25; Config.volume = FESTAI_SetVolume(Player, Config.volume);poosh();ShowStatus(0,1);break;
     case 's': Config.volume+=25; Config.volume = FESTAI_SetVolume(Player, Config.volume);poosh();ShowStatus(0,1);break;
     case '_':
     case '-': Config.volume--; FESTAI_SetVolume(Player,Config.volume);poosh();ShowStatus(0,1);break;
     case '+':
     case '=': Config.volume++; FESTAI_SetVolume(Player,Config.volume);poosh();ShowStatus(0,1);break;
     case 'p': TogglePause();break;
     case 'q': goto exito;

     /* Alternate song selection keys.  Especially needed for DOS port. */
     case '\'':current=FESTAI_SongControl(Player,10,0);poosh(); lastms = ~0;frames_written=0;ShowStatus(1,1);break;
     case ';':current=FESTAI_SongControl(Player,-10,0);poosh(); lastms = ~0;frames_written=0;ShowStatus(1,1);break;
     case '.':current=FESTAI_SongControl(Player,1,0);poosh(); lastms = ~0;frames_written=0;ShowStatus(1,1);break;
     case ',':current=FESTAI_SongControl(Player,-1,0);poosh(); lastms = ~0;frames_written=0;ShowStatus(1,1);break;
    }
    t[2]=t[1];
    t[1]=t[0];
  }

 }

  exito:
  if(WRFilename)
  {
      FCEUI_EndWaveRecord();
      free(WRFilename);
      WRFilename = 0;
  }
  poosh();
  FESTAI_Close(Player);
  if(Output) Output->Close(Output);
  Output = 0;
 }

 rmode();

 free(DriverTypes);
 if(Interface) Interface->Destroy(Interface);
 return(0);
}
Example #2
0
static bool RunSexyALTest(SexyAL *interface, SexyAL_buffering *buffering, const char *device, int driver_type)
{
 static const int to_format[9] = 
 {
  SEXYAL_FMT_PCMU8,
  SEXYAL_FMT_PCMS8,
  SEXYAL_FMT_PCMU16,
  SEXYAL_FMT_PCMS16,

  SEXYAL_FMT_PCMU24,
  SEXYAL_FMT_PCMS24,
  SEXYAL_FMT_PCMU32,
  SEXYAL_FMT_PCMS32,

  SEXYAL_FMT_PCMFLOAT
 };

 static const char *to_format_name[9] = 
 {
  "8-bit unsigned",
  "8-bit signed",
  "16-bit unsigned",
  "16-bit signed",
  "24-bit unsigned",
  "24-bit signed",
  "32-bit unsigned",
  "32-bit signed",
  "float"
 };

 // TODO: byte order format conversion.
 // TODO: source format.
 const int rate = 48000;
 const int numframes = (rate / 2 + 1) &~ 1;

 for(int src_channels = 1; src_channels <= 2; src_channels++)
 {
  for(int dest_channels = 1; dest_channels <= 2; dest_channels++)
  {
   //for(int src_format = 0; src_format < 9; src_format++)
   int src_format = 3;
   {
    for(int dest_format = 0; dest_format < 9; dest_format++)
    {
     printf("Source Format: %s, Source Channels: %d --- Dest Format: %s, Dest Channels: %d\n\n", to_format_name[src_format], src_channels, to_format_name[dest_format], dest_channels);

     memset(&format,0,sizeof(format));

     Interface = (SexyAL *)SexyAL_Init(0);
     DriverTypes = Interface->EnumerateTypes(Interface);

     format.sampformat = to_format[dest_format];
     format.channels = dest_channels;
     format.revbyteorder = 0;
     format.rate = rate;

     buffering->buffer_size = 0;
     buffering->period_size = 0;
     buffering->latency = 0;
     buffering->bt_gran = 0;

     if(!(Output=Interface->Open(Interface, device, &format, buffering, driver_type)))
     {
      MDFND_PrintError(_("Error opening a sound device."));
      Interface->Destroy(Interface);
      Interface=0;
      return(0);
     }

     if(format.sampformat != to_format[dest_format])
      printf("Warning: Could not set desired device format.\n");

     if(format.channels != dest_channels)
      printf("Warning: Could not set desired device channel count.\n");

     if(format.rate != rate)
      printf("Warning: Could not set desired device rate.\n");

     format.sampformat = to_format[src_format];
     format.channels = src_channels;
     format.revbyteorder = 0;
     format.rate = rate;

     Output->SetConvert(Output, &format);

     if(to_format[src_format] == SEXYAL_FMT_PCMS16)
     {
      int16 samples[numframes * src_channels];

      for(int i = 0; i < numframes; i++)
      {
       int16 sval = 4095 * sin((double)i * 440 * M_PI * 2 / rate);
       
       for(int ch = 0; ch < src_channels; ch++)
        samples[i * src_channels + ch] = sval;
      }
      // Write half in one go, the rest in small chunks.
      if(!Output->Write(Output, samples, numframes / 2))
	printf("Write count error 0\n");

      for(int i = numframes / 2; i < numframes; i += 100)
      {
       int32 towrite = numframes - i;
 
       if(towrite > 100)
        towrite = 100;

       if(!Output->Write(Output, samples + i * src_channels, towrite))
        printf("Write count error 1\n");
      }
     }
     Output->Close(Output);
     Interface->Destroy(Interface);
     sleep(1);
    }
   }
  }
 }
}
Example #3
0
bool InitSound(MDFNGI *gi)
{
 SoundRate = 0;

 memset(&format,0,sizeof(format));
 memset(&buffering,0,sizeof(buffering));

 Interface = (SexyAL *)SexyAL_Init(0);
 DriverTypes = Interface->EnumerateTypes(Interface);

 format.sampformat = SEXYAL_FMT_PCMS16;

 assert(gi->soundchan);
 format.channels = gi->soundchan;

 format.revbyteorder = 0;

 format.rate = gi->soundrate ? gi->soundrate : MDFN_GetSettingUI("sound.rate");

 buffering.ms = MDFN_GetSettingUI("sound.buffer_time");
 buffering.period_us = MDFN_GetSettingUI("sound.period_time");

 std::string zedevice = MDFN_GetSettingS("sound.device");
 std::string zedriver = MDFN_GetSettingS("sound.driver");

 CurDriverIndex = -1;

 if(!strcasecmp(zedriver.c_str(), "default"))
  CurDriverIndex = 0;
 else
 {
  for(int x = 0; DriverTypes[x].short_name; x++)
  {
   if(!strcasecmp(zedriver.c_str(), DriverTypes[x].short_name))
   {
    CurDriverIndex = x;
    break;
   }
  }
 }

 MDFNI_printf(_("\nInitializing sound...\n"));
 MDFN_indent(1);

 if(CurDriverIndex == -1)
 {
  MDFN_printf(_("\nUnknown sound driver \"%s\".  Supported sound drivers:\n"), zedriver.c_str());

  MDFN_indent(2);
  for(int x = 0; DriverTypes[x].short_name; x++)
  {
   MDFN_printf("%s\n", DriverTypes[x].short_name);
  }
  MDFN_indent(-2);
  MDFN_printf("\n");
  Interface->Destroy(Interface);
  Interface = NULL;
  MDFN_indent(-1);
  return(FALSE);
 }

 MDFNI_printf(_("Using \"%s\" audio driver with device \"%s\":"),DriverTypes[CurDriverIndex].name, zedevice.c_str());
 MDFN_indent(1);

 //RunSexyALTest(Interface, &buffering, zedevice.c_str(), DriverTypes[CurDriverIndex].type);
 //exit(1);

 if(!(Output=Interface->Open(Interface, zedevice.c_str(), &format, &buffering, DriverTypes[CurDriverIndex].type)))
 {
  MDFND_PrintError(_("Error opening a sound device."));
  Interface->Destroy(Interface);
  Interface=0;
  MDFN_indent(-2);
  return(FALSE);
 }

 if(format.rate<8192 || format.rate > 48000)
 {
  MDFND_PrintError(_("Set rate is out of range [8192-48000]"));
  KillSound();
  MDFN_indent(-2);
  return(FALSE);
 }
 MDFNI_printf(_("\nBits: %u\nRate: %u\nChannels: %u\nByte order: CPU %s\nBuffer size: %u sample frames(%f ms)\n"), (format.sampformat>>4)*8,format.rate,format.channels,format.revbyteorder?"Reversed":"Native", buffering.buffer_size, (double)buffering.buffer_size * 1000 / format.rate);
 MDFNI_printf(_("Latency: %u sample frames(%f ms)\n"), buffering.latency, (double)buffering.latency * 1000 / format.rate);

 if(buffering.period_size)
 {
  int64_t pt_test_result = ((int64_t)buffering.period_size * (1000 * 1000) / format.rate);

  MDFNI_printf(_("Period size: %u sample frames(%f ms)\n"), buffering.period_size, (double)buffering.period_size * 1000 / format.rate);

  if(pt_test_result > 5333)
  {
   MDFN_indent(1);
   MDFN_printf(_("Warning: Period time is too large(it should be <= ~5.333ms).  Video will appear very jerky.\n"));
   MDFN_indent(-1);
  }
 }
 format.sampformat=SEXYAL_FMT_PCMS16;
 format.channels=gi->soundchan?gi->soundchan:1;
 format.revbyteorder=0;

 //format.rate=gi->soundrate?gi->soundrate:soundrate;

 Output->SetConvert(Output, &format);

 EmuModBufferSize = (500 * format.rate + 999) / 1000;
 EmuModBuffer = (int16 *)calloc(sizeof(int16) * format.channels, EmuModBufferSize);

 SoundRate = format.rate;
 MDFN_indent(-2);

 return(1);
}