#import "TunePlayer.h"
#import "AppDelegate.h"

static NSString *soundfonts[] = {
  @"banjo.sf2",
  @"guitar.sf2",
  @"violin.sf2",
  @"flute.sf2",
  @"accordion.sf2",
  @"piano.sf2",
  @"whistle.sf2",
  @"harp.sf2",
};

@implementation TunePlayer

@synthesize filePath, transpose;

static void player_notify_callback( fluid_player_t* player, void *data )
{
  TunePlayer* tunePlayer = (TunePlayer*)data;
  [tunePlayer performSelectorOnMainThread:@selector(playerFinished:) withObject:tunePlayer waitUntilDone:NO];
}

+ (TunePlayer *)tunePlayer;
{
  static TunePlayer *player;
  if ( !player )
    player = [[TunePlayer alloc] init];
  return player;
}

- (id)init {
  self = [super init];
  if ( self ) {
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    speed = appDelegate.playerSpeed;
    voice = appDelegate.playerVoice;
    volume = appDelegate.playerVolume;
    settings = NULL;
    synth = NULL;
    adriver = NULL;
  }
  return self;
}

- (void)dealloc {
  if ( adriver )
    delete_fluid_audio_driver( adriver );
  if ( synth )
    delete_fluid_synth( synth );
  if ( settings )
    delete_fluid_settings( settings );
  [super dealloc];
}

- (int)numVoices
{
  return 8;
}

- (NSString *)voiceName:(int)v
{
  return soundfonts[v];
}

- (void)setSpeed:(float)s
{
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  appDelegate.playerSpeed = speed = s;
  if ( player )
    fluid_player_set_speed_multiplier( player, pow( 2.0, speed ) );
}

- (float)speed
{
  return speed;
}

- (void)setVoice:(int)v
{
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  appDelegate.playerVoice = voice = v;
  if ( synth )
    for ( int channel = 0; channel < 15; channel++ )
      fluid_synth_program_select(synth, channel, sfont_id[voice], 0, 0);
}

- (int)voice
{
  return voice;
}

- (void)setVolume:(float)v
{
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  appDelegate.playerVolume = volume = v;
  if ( settings )
    fluid_settings_setnum( settings, "synth.gain", volume * 0.25 );
}

- (float)volume
{
  return volume;
}

- (void)play
{
  [self stop];
  if ( !settings ) {
    settings = new_fluid_settings();

    fluid_settings_setstr(settings, "audio.driver", "coreaudio");
    fluid_settings_setstr(settings, "audio.sample-format", "16bits");
    fluid_settings_setnum(settings, "synth.sample-rate", 8000);

    synth = new_fluid_synth(settings);
    adriver = new_fluid_audio_driver(settings, synth);

    for ( int i = 0; i < [self numVoices]; i++ ) {
      NSString *sfFile = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:soundfonts[i]];
      sfont_id[i] = fluid_synth_sfload(synth, [sfFile UTF8String], 0);
    }
  }
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  player = new_fluid_player( synth );
  fluid_player_set_notify_callback( player, player_notify_callback, self );
  for ( int channel = 0; channel < 15; channel++ )
    fluid_synth_program_select(synth, channel, sfont_id[voice], 0, 0);
  fluid_player_add( player, (char *)[filePath UTF8String] );
  fluid_player_set_speed_multiplier( player, pow( 2.0, speed ) );
  fluid_settings_setnum( settings, "synth.gain", volume * 0.25 );
  fluid_player_set_loop( player, appDelegate.loopPlayback );
  fluid_player_play( player );
}

- (void)stop
{
  if ( player ) {
    fluid_player_stop(player);
    fluid_player_join(player);
    delete_fluid_player(player);
    fluid_synth_system_reset( synth );
    player = NULL;
  }
}

- (void)pause
{
  //FIXME-testing
  static int paused = 0;
  if ( player )
    fluid_player_pause( player, !paused );
  paused = !paused;
}

- (BOOL)playing
{
  return player != NULL;
}

- (void)playerFinished:(id)sender
{
  [[NSNotificationCenter defaultCenter] postNotificationName:@"playerFinished" object:self];
  [self stop];
}

@end
