from sugar.activity import activity

from Csound import *
from CsoundServer import *


import random
import sys, os
import gtk

import gobject
import time
import math

class CSPitchTrackActivity(activity.Activity):
    orchestra = """
    nchnls = 2

turnon 10
    
instr	10

    iupdte = 0.05
    ilo = 7
    ihi = 9
    idbthresh = 10
    ifrqs = 12
    iconf = 10
    istrt = 8

    kCounter init 0

    aIn1, aIn2  ins 

    koct, kamp   pitch  aIn1, iupdte, ilo, ihi, idbthresh, ifrqs, iconf, istrt

    kcps = cpsoct(koct)
    
    kcps    portk kcps, 0.25
    kamp    portk kamp, 0.25
        
    ; speed limit the output so we don't flood our socket
    if kCounter < 10 kgoto done 

        outvalue "amp", kamp
        outvalue "pitch", kcps

        kCounter = 0
done:
    kCounter = kCounter + 1

endin
    """

    def destroy(self, data=None):
        print "Destroy"
        #self.csound.shutdownServer()
        #return True

    def __init__(self, handle):
        print "Activity"
        activity.Activity.__init__(self, handle)
               
        #self.connect('destroy', self.destroy)
        

        self.set_title('CSRecorder')
                
        # Creates the Toolbox. It contains the Activity Toolbar, which is the
        # bar that appears on every Sugar window and contains essential
        # functionalities, such as the 'Collaborate' and 'Close' buttons.
        toolbox = activity.ActivityToolbox(self)
        self.set_toolbox(toolbox)
        toolbox.show()
        
        self.plot2D = Plot2D()
        self.plot2D.set_size_request(1180, 700)
                            
        self.layout = gtk.Layout()
        self.layout.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#C0C0C0"))        
        
        self.minPitch = 220
        self.maxPitch = 440
        
        self._minPitch = 180
        self._maxPitch = 600
                        
        # value, lower, upper, step_increment, page_increment, page_size
        self.minPitchSlider = gtk.HScale(gtk.Adjustment(self.minPitch, self._minPitch, self._maxPitch, 1.0, 1.0, 1.0))
        self.minPitchSlider.connect("value_changed", self.minPitchChanged)
        self.minPitchSlider.set_update_policy(gtk.UPDATE_CONTINUOUS)
        self.minPitchSlider.set_size_request(300, 60)

        # value, lower, upper, step_increment, page_increment, page_size
        self.maxPitchSlider = gtk.HScale(gtk.Adjustment(self.maxPitch, self._minPitch, self._maxPitch, 1.0, 1.0, 1.0))
        self.maxPitchSlider.connect("value_changed", self.maxPitchChanged)
        self.maxPitchSlider.set_update_policy(gtk.UPDATE_CONTINUOUS)
        self.maxPitchSlider.set_size_request(300, 60)


        self.layout.put(self.plot2D, 10, 10)
        self.layout.put(gtk.Label("min"), 50, 730)        
        self.layout.put(self.minPitchSlider, 100, 730)        
        self.layout.put(gtk.Label("max"), 450, 735)        
        self.layout.put(self.maxPitchSlider, 500, 730)                

        self.xVal = gtk.Label("x=?")
        self.yVal = gtk.Label("y=?")        
        self.layout.put(self.xVal, 900, 735)
        self.layout.put(self.yVal, 1000, 735)

        self.layout.show_all()

        
        server = CsoundServer()
        fd = server.launch(debugMode=0, sampleRate=22050)
        if fd != None:
            gobject.io_add_watch(fd.fileno(), gobject.IO_IN, self.serverMessages, fd)


        self.set_canvas(self.layout)

        # Create our instance        
        self.csound = Csound("PitchTrack")
        self.csound.setMessageCallback(self.csoundMessages)
        self.csound.setupOrchestraAsString(self.orchestra)
        self.csound.registerChannel("amp", self.ampUpdate)            
        self.csound.registerChannel("pitch", self.pitchUpdate)    
        self.csound.setSampleRate(22050)
        self.csound.setControlRate(220.5)        
        self.csound.initialize()
        self.csound.perform()

    def minPitchChanged(self, widget, userData = None):
        self.minPitch = widget.get_value()
        
    def maxPitchChanged(self, widget, userData = None):        
        self.maxPitch = widget.get_value()
                
    def pitchUpdate(self, message):
        hz = message.argument(0)
        x = (hz - self.minPitch) / (self.maxPitch - self.minPitch)
        if x < 0.1:
            x = 0.1
        if x > 0.9:
            x = 0.9
            
        self.x = x # save
        
        gobject.idle_add(self.idleUpdatePitch, hz)
                
    def idleUpdatePitch(self, hz):
        self.xVal.set_label("%.2f" % hz)
    
    def idleUpdateAmp(self, y):
        self.yVal.set_label("%.2f" % y)
                    
        if y > 0.01:
            # use last x
            self.plot2D.setPoint( self.x, y )            

        
    def ampUpdate(self, message):        
        y = message.argument(0) / 10000
        
        gobject.idle_add(self.idleUpdateAmp, y)
                

        
    def serverMessages(self, source, condition, userData = None):
        print "SERVER:", userData.readline(),
        return True

    def csoundMessages(self, message):
        message.display("Csound")

class Plot2D(gtk.DrawingArea):
    def __init__(self):
        gtk.DrawingArea.__init__(self)
        self.connect("expose_event", self.expose)
        
        self.trace = [[0,0], [0,0], [0,0], [0,0], [0,0]]
        
        self.setX(0)
        self.setY(0)

    def expose(self, widget, event):
        #print "expose", event.area.x, event.area.y, event.area.width, event.area.height        
        self.context = widget.window.cairo_create()        
        # set a clip region for the expose event
        self.context.rectangle(event.area.x, event.area.y,
                               event.area.width, event.area.height)
        self.context.clip()        
        self.draw(self.context)        
        return False

    def setPoint(self, x, y):
        self.xPos = x
        self.yPos = y
        self.redrawAll()
    
    def setX(self, val):
        self.xPos = val
        self.redrawAll()
        
    def setY(self, val):
        self.yPos = val
        self.redrawAll()
                
    def drawBall(self, context, x, y, radius, alpha):
        context.arc(x, y, radius, 0, 2 * math.pi)
        context.set_source_rgba(1, 1, 1, alpha)
        context.fill_preserve()
        context.set_source_rgba(0, 0, 0, alpha)
        context.stroke()

                
    def draw(self, context):        
        rect = self.get_allocation()

        maxCircles = 10    
        radius = 35

        a = 1.0 / maxCircles
        
        #for vals in self.trace:
        #    self.drawBall(context, vals[0], vals[1], radius, a)
        #    a += 1.0 / maxCircles
                
        x = rect.width * self.xPos
        y = rect.height - (rect.height * self.yPos)
        self.drawBall(context, x, y, radius, 1.0)

        #self.trace[0] = [x, y]
        
    def redrawAll(self):        
        rect = self.get_allocation()
        self.queue_draw_area(0, 0, rect.width, rect.height)
