# -*- coding: utf-8 -*-
"""
module de wrapping du synthétiseur

$Id$
$URL$
"""
from os.path import realpath, sep, exists
from  fluidsynth import Synth as FSynth
from fluidsynth import fluid_settings_setnum
from log import console, envLogger, eventLogger
import pygame
import events
from config import SOUND_FONT

class Synth(FSynth) :
    """
    Interface fluidsynth avec les adaptations suivantes :
    - la soundfont FluidR3_GM.sf2 est chargée par défaut
    - le constructeur démarre le synthé
    - octaviation
    """
    
    def __init__(self, gain=0.2, samplerate=44100, sfPath='', driver=None) :
        FSynth.__init__(self, gain=gain, samplerate=samplerate)
        
        if not sfPath :
            sfPath = SOUND_FONT
        assert exists(sfPath)
        
        self._gain = gain

        self.start(driver=driver)
        self.fsid = self.sfload(sfPath)
        self._octaveAjusts = {}
        console.debug('démarrage du synthétiseur')
        envLogger.info('soundfont : %s', sfPath)
    
    def __del__(self) :
        console.debug('arrêt du synthétiseur')
        self.delete()
    
    def gain(self, gain) :
        self._gain = gain
        fluid_settings_setnum(self.settings, 'synth.gain', self._gain)
    
    def inc_gain(self, step = 0.1) :
        self._gain = self._gain + step
        if self._gain > 5 :
            self._gain = 5
        self.gain(self._gain)
    
    def dec_gain(self, step = 0.1) :
        self._gain = self._gain - step
        if self._gain < 0 :
            self._gain = 0
        self.gain(self._gain)

    def adjust_octave(self, chan, octave) :
        '''
        Abaisse ou élève les notes de n octave
        '''
        self._octaveAjusts[chan] = octave
    
    def sfunload(self, update_midi_preset=0):
        FSynth.sfunload(self, self.fsid, update_midi_preset=update_midi_preset)
    
    def program_select(self, chan, bank, preset):
        FSynth.program_select(self, chan, self.fsid, bank, preset)

    def sfont_select(self, chan):
        FSynth.sfont_select(self, chan, self.fsid)


    # on loggue les noteon / noteoff en utilisant les événements pygame
    # mais ils ne sont pas postés -> on fait ça pour que le log de l'événement
    # et l'exécution du noteon/off soit effectué au sein de la même itération
    # de la boucle principale.
    
    def noteon(self, chan, key, vel):
        key = key + self._octaveAjusts.get(chan, 0) * 12
        FSynth.noteon(self, chan, key, vel)
        evt = pygame.event.Event(events.NOTEON, chan=chan, key=key, vel=vel)
        eventLogger.info(evt)
        #pygame.event.post(evt)
    
    def noteoff(self, chan, key) :
        key = key + self._octaveAjusts.get(chan, 0) * 12
        FSynth.noteoff(self, chan, key)
        evt = pygame.event.Event(events.NOTEOFF, chan=chan, key=key)
        eventLogger.info(evt)
        #pygame.event.post(evt)
