diff options
author | olipet <olpc@localhost.localdomain> | 2007-01-15 11:02:19 (GMT) |
---|---|---|
committer | olipet <olpc@localhost.localdomain> | 2007-01-15 11:02:19 (GMT) |
commit | 20c60d6a435599dad56e97b0ce9d7efc6f02c4d4 (patch) | |
tree | 9039ee1a1be14f76923c3457d98bf6b7ba585a7a | |
parent | d94ce096e869d1802f709c64fbc0fc70ab143fbf (diff) | |
parent | 158d399d97c52554659f1725425700724eafc514 (diff) |
Merge branch 'master' of git+ssh://olipet@dev.laptop.org/git/projects/tamtam
-rw-r--r-- | Config.py | 39 | ||||
-rw-r--r-- | Edit/MainWindow.py | 8 | ||||
-rw-r--r-- | Edit/NoteInterface.py | 73 | ||||
-rw-r--r-- | Edit/TrackInterface.py | 222 | ||||
-rwxr-xr-x | Resources/Images/note.png | bin | 0 -> 3677 bytes | |||
-rwxr-xr-x | Resources/Images/noteSelected.png | bin | 0 -> 3904 bytes | |||
-rwxr-xr-x | Resources/Images/trackBG.png | bin | 0 -> 4387 bytes | |||
-rwxr-xr-x | Resources/Images/trackBGDrum.png | bin | 0 -> 4717 bytes | |||
-rwxr-xr-x | Resources/Images/trackBGDrumSelected.png | bin | 0 -> 4511 bytes | |||
-rwxr-xr-x | Resources/Images/trackBGSelected.png | bin | 0 -> 4215 bytes | |||
-rw-r--r-- | Util/Sound.py | 276 | ||||
-rwxr-xr-x[-rw-r--r--] | scripts/olpc_get_stuff.sh | 10 |
12 files changed, 476 insertions, 152 deletions
@@ -2,6 +2,16 @@ import os +if os.path.isfile("DEBUG"): + f = open("DEBUG") + l = f.read(10) + if len(l): DEBUG = int( l ) + else: DEBUG = 99 +else: + DEBUG = False +print "Debug Level %d" % (DEBUG) + + TAM_TAM_ROOT = os.path.dirname(os.path.abspath(__file__)) PREF_DIR = '/tamtam' print 'INFO: loaded TAMTAM_ROOT=%s' % TAM_TAM_ROOT @@ -350,24 +360,33 @@ UNLOAD_TABLES_COMMAND = \ LANGUAGE = 'En' IMAGE_ROOT = TAM_TAM_ROOT + '/Resources/Images/' -NOTE_HEIGHT = 6 # pixels -NOTE_BORDER_SIZE = 1 -NOTE_BORDER_SIZE_DIV2 = NOTE_BORDER_SIZE/2.0 +NOTE_HEIGHT = 9 # pixels +NOTE_IMAGE_PADDING = 6 +NOTE_IMAGE_PADDING_MUL2 = NOTE_IMAGE_PADDING*2 +NOTE_IMAGE_TAIL = 1059 +NOTE_IMAGE_ENDLENGTH = 12 MAIN_WINDOW_PADDING = 5 -TRACK_SPACING = 1 -BORDER_SIZE = 2 -BORDER_SIZE_DIV2 = BORDER_SIZE/2.0 -BORDER_SIZE_MUL2 = BORDER_SIZE*2 -BEAT_LINE_SIZE = 1 -BEAT_LINE_SIZE_DIV2 = BEAT_LINE_SIZE/2.0 +TRACK_SPACING = 4 +TRACK_SPACING_DIV2 = TRACK_SPACING//2 +TRACK_COLORS = [ ( "#00591B", "#00E847" ), \ + ( "#6F1200", "#E72500" ), \ + ( "#004682", "#0090EA" ), \ + ( "#716D00", "#F9EF00" ), \ + ( "#37187B", "#4A00ED" ) ] +BEAT_COLOR = "#999999" +BEAT_LINE_SIZE = 2 +PLAYHEAD_COLOR = "#666666" PLAYHEAD_SIZE = 2 -PLAYHEAD_SIZE_DIV2 = PLAYHEAD_SIZE/2.0 +MARQUEE_COLOR = "#FFFFFF" +MARQUEE_SIZE = 2 INST_BCK_COLOR = '#979DA8' PANEL_BCK_COLOR = '#FFFFFF' PANEL_COLOR = '#707F93' PANEL_RADIUS = 10 +BORDER_SIZE = 2 + PAGE_BORDER_SIZE = 2 PAGE_SELECTED_BORDER_SIZE = 5 PAGE_WIDTH = 100 diff --git a/Edit/MainWindow.py b/Edit/MainWindow.py index fe6a89d..9270fab 100644 --- a/Edit/MainWindow.py +++ b/Edit/MainWindow.py @@ -265,7 +265,7 @@ class MainWindow( gtk.EventBox ): self._data['volume'] = Config.DEFAULT_VOLUME self._data['page_beats'] = [nbeats for p in range(npages)] - self._data['tempo'] = Config.DEFAULT_TEMPO + self._data['tempo'] = Config.PLAYER_TEMPO self._data['ticks_per_sec'] = self._data['tempo'] * 0.2 # 12 BPM / 60 SPM self._data['tune'] = [] self._data['notebin'] = [] @@ -466,7 +466,7 @@ class MainWindow( gtk.EventBox ): self.noteLooper = NoteLooper( 0.2, - Config.DEFAULT_TEMPO * 0.2 #0.2 currently converts beats per second to seconds_per_tick + Config.PLAYER_TEMPO * 0.2 #0.2 currently converts beats per second to seconds_per_tick ) self.csnd.startTime() self.noteLooper.startTime() @@ -1012,6 +1012,10 @@ class MainWindow( gtk.EventBox ): return False def destroy( self, widget ): + + if Config.DEBUG: + print TP.PrintAll() + gtk.main_quit() def updateNumberOfBars( self, widget = None, data = None ): diff --git a/Edit/NoteInterface.py b/Edit/NoteInterface.py index 43ae376..c49a8d8 100644 --- a/Edit/NoteInterface.py +++ b/Edit/NoteInterface.py @@ -6,7 +6,7 @@ import Config class NoteInterface: - def __init__( self, parent, page, track, note, pitch, onset, duration, amplitude): + def __init__( self, parent, page, track, note, pitch, onset, duration, amplitude, image, imageSelected, colors ): self.parent = parent self.page = page self.track = track @@ -16,8 +16,10 @@ class NoteInterface: self.y = 0 self.width = 1 self.height = Config.NOTE_HEIGHT - - self.updateParams( pitch, onset, duration, amplitude ) + self.imgX = 0 + self.imgY = 0 + self.imgWidth = 1 + self.imgHeight = self.height + Config.NOTE_IMAGE_PADDING_MUL2 self.selected = False self.potentialDeselect = False @@ -25,6 +27,12 @@ class NoteInterface: self.lastDragO = 0 self.lastDragP = 0 self.lastDragD = 0 + + self.image = image + self.imageSelected = imageSelected + self.baseColors = colors + + self.updateParams( pitch, onset, duration, amplitude ) def destroy( self ): # nothing to do? @@ -37,7 +45,10 @@ class NoteInterface: self.end = onset + duration self.amplitude = amplitude - self.bgColour = 1 - ( ( self.amplitude * 0.7 ) + 0.3 ) + r = self.baseColors[0][0] + int(self.baseColors[1][0]*amplitude) + g = self.baseColors[0][1] + int(self.baseColors[1][1]*amplitude) + b = self.baseColors[0][2] + int(self.baseColors[1][2]*amplitude) + self.color = self.parent.drawingArea.get_colormap().alloc_color( r, g, b, True, True ) self.updateTransform( False ) @@ -55,22 +66,25 @@ class NoteInterface: def updateTransform( self, onlyX ): if self.page == self.parent.curPage: - oldX = self.x - oldY = self.y - oldEndX = self.x + self.width + oldX = self.imgX + oldY = self.imgY + oldEndX = self.imgX + self.imgWidth origin = self.parent.getTrackOrigin( self.track ) self.x = self.parent.ticksToPixels( self.onset ) self.width = self.parent.ticksToPixels( self.end ) - self.x + self.imgWidth = self.width + Config.NOTE_IMAGE_PADDING_MUL2 self.x += origin[0] + self.imgX = self.x - Config.NOTE_IMAGE_PADDING if not onlyX: self.y = self.parent.pitchToPixels( self.pitch ) + origin[1] - + self.imgY = self.y - Config.NOTE_IMAGE_PADDING + if self.page == self.parent.curPage: - x = min( self.x, oldX ) - y = min( self.y, oldY ) - endx = max( self.x + self.width, oldEndX ) - endy = max( self.y, oldY ) + self.height + x = min( self.imgX, oldX ) + y = min( self.imgY, oldY ) + endx = max( self.imgX + self.imgWidth, oldEndX ) + endy = max( self.imgY, oldY ) + self.imgHeight self.parent.invalidate_rect( x, y, endx-x, endy-y ) def updateDragLimits( self, dragLimits, leftBound, rightBound, widthBound ): @@ -237,7 +251,7 @@ class NoteInterface: if self.selected != state: self.selected = state if self.page == self.parent.curPage: - self.parent.invalidate_rect( self.x, self.y, self.width, self.height ) + self.parent.invalidate_rect( self.imgX, self.imgY, self.imgWidth, self.imgHeight ) return True # state changed return False # state is the same @@ -247,32 +261,17 @@ class NoteInterface: #======================================================= # Selection - def draw( self, context, startX, stopX ): - if stopX < self.x: return False # we don't need to draw and no one after us will draw - if startX > self.x + self.width: return True # we don't need to draw, but maybe a later note does - - - if False: - context.set_line_width( Config.NOTE_BORDER_SIZE ) + def draw( self, win, gc, startX, stopX ): + if stopX < self.imgX: return False # we don't need to draw and no one after us will draw + if startX > self.imgX + self.imgWidth: return True # we don't need to draw, but maybe a later note does - context.move_to( self.x + Config.NOTE_BORDER_SIZE_DIV2, self.y + Config.NOTE_BORDER_SIZE_DIV2 ) - context.rel_line_to( self.width - Config.NOTE_BORDER_SIZE, 0 ) - context.rel_line_to( 0, self.height - Config.NOTE_BORDER_SIZE ) - context.rel_line_to( -self.width + Config.NOTE_BORDER_SIZE, 0 ) - context.close_path() - - context.rectangle(self.x, self.y, self.width, self.height ) + gc.foreground = self.color + win.draw_rectangle( gc, True, self.x+1, self.y+1, self.width-2, self.height-2 ) - #background - context.set_source_rgb( self.bgColour, self.bgColour, self.bgColour ) - #context.fill_preserve() - context.fill() - return True - - #border - if self.selected: context.set_source_rgb( 1, 1, 1 ) - else: context.set_source_rgb( 0, 0, 0 ) - context.stroke() + if self.selected: img = self.imageSelected + else: img = self.image + win.draw_pixbuf( gc, img, 0, 0, self.imgX, self.imgY, self.imgWidth-Config.NOTE_IMAGE_ENDLENGTH, self.imgHeight, gtk.gdk.RGB_DITHER_NONE ) + win.draw_pixbuf( gc, img, Config.NOTE_IMAGE_TAIL, 0, self.imgX+self.imgWidth-Config.NOTE_IMAGE_ENDLENGTH, self.imgY, Config.NOTE_IMAGE_ENDLENGTH, self.imgHeight, gtk.gdk.RGB_DITHER_NONE ) return True # we drew something diff --git a/Edit/TrackInterface.py b/Edit/TrackInterface.py index cb46c0c..4522c0b 100644 --- a/Edit/TrackInterface.py +++ b/Edit/TrackInterface.py @@ -29,7 +29,7 @@ class TrackInterface( gtk.EventBox ): gtk.EventBox.__init__( self ) self.drawingArea = gtk.DrawingArea() - self.drawingAreaDirty = False # is the drawingArea waiting to draw? + self.drawingAreaDirty = False # are we waiting to draw? self.add( self.drawingArea ) self.dirtyRectToAdd = gtk.gdk.Rectangle() # used by the invalidate_rect function @@ -61,7 +61,7 @@ class TrackInterface( gtk.EventBox ): self.marqueeLoc = False # current drag location of the marquee self.marqueeRect = [[0,0],[0,0]] - self.playheadX = 0 + self.playheadX = Config.TRACK_SPACING_DIV2 self.cursor = { \ "default": None, \ @@ -76,12 +76,69 @@ class TrackInterface( gtk.EventBox ): self.connect( "size-allocate", self.size_allocate ) - self.drawingArea.connect( "expose-event", self.draw ) + self.drawingArea.connect( "expose-event", self.expose ) self.connect( "button-press-event", self.handleButtonPress ) self.connect( "button-release-event", self.handleButtonRelease ) self.connect( "motion-notify-event", self.handleMotion ) self.onNoteDrag = onNoteDrag + + # prepare drawing stuff + hexToInt = { "0":0, "1":1, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "A":10, "B":11, "C":12, "D":13, "E":14, "F":15, "a":10, "b":11, "c":12, "d":13, "e":14, "f":15 } + self.trackColors = [] + for i in Config.TRACK_COLORS: + low = ( 256*(hexToInt[i[0][1]]*16+hexToInt[i[0][2]]), 256*(hexToInt[i[0][3]]*16+hexToInt[i[0][4]]), 256*(hexToInt[i[0][5]]*16+hexToInt[i[0][6]]) ) + high = ( 256*(hexToInt[i[1][1]]*16+hexToInt[i[1][2]]), 256*(hexToInt[i[1][3]]*16+hexToInt[i[1][4]]), 256*(hexToInt[i[1][5]]*16+hexToInt[i[1][6]]) ) + delta = ( high[0]-low[0], high[1]-low[1], high[2]-low[2] ) + self.trackColors.append( (low, delta) ) + + colormap = self.drawingArea.get_colormap() + self.beatColor = colormap.alloc_color( Config.BEAT_COLOR, True, True ) + self.playheadColor = colormap.alloc_color( Config.PLAYHEAD_COLOR, True, True ) + self.marqueeColor = colormap.alloc_color( Config.MARQUEE_COLOR, True, True ) + + self.image = {} + img = gtk.Image() + win = gtk.gdk.get_default_root_window() + self.gc = gtk.gdk.GC( win ) + + def prepareDrawable( name ): + img.set_from_file( Config.IMAGE_ROOT+name+".png" ) + pix = img.get_pixbuf() + self.image[name] = gtk.gdk.Pixmap( win, pix.get_width(), pix.get_height() ) + self.image[name].draw_pixbuf( self.gc, pix, 0, 0, 0, 0, pix.get_width(), pix.get_height(), gtk.gdk.RGB_DITHER_NONE ) + def preparePixbuf( name ): + newimg = gtk.Image() + newimg.set_from_file( Config.IMAGE_ROOT+name+".png" ) + self.image[name] = newimg.get_pixbuf() + + prepareDrawable( "trackBG" ) + prepareDrawable( "trackBGSelected" ) + prepareDrawable( "trackBGDrum" ) + prepareDrawable( "trackBGDrumSelected" ) + preparePixbuf( "note" ) + preparePixbuf( "noteSelected" ) + + # define dimensions + self.width = self.trackFullWidth = self.image["trackBG"].get_size()[0] + self.trackWidth = self.width - Config.TRACK_SPACING + self.trackFullHeight = self.image["trackBG"].get_size()[1] + self.trackHeight = self.trackFullHeight - Config.TRACK_SPACING + self.trackFullHeightDrum = self.image["trackBGDrum"].get_size()[1] + self.trackHeightDrum = self.trackFullHeightDrum - Config.TRACK_SPACING + self.height = self.trackHeight*(Config.NUMBER_OF_TRACKS-1) + self.trackHeightDrum + Config.TRACK_SPACING*Config.NUMBER_OF_TRACKS + self.trackLimits = [] + self.trackRect = [] + self.drumIndex = Config.NUMBER_OF_TRACKS-1 + for i in range(self.drumIndex): + start = i*(self.trackFullHeight) + self.trackLimits.append( (start,start+self.trackFullHeight) ) + self.trackRect.append( gtk.gdk.Rectangle(Config.TRACK_SPACING_DIV2,start+Config.TRACK_SPACING_DIV2, self.trackWidth, self.trackHeight ) ) + self.trackLimits.append( ( self.height - self.trackFullHeightDrum, self.height ) ) + self.trackRect.append( gtk.gdk.Rectangle( Config.TRACK_SPACING_DIV2, self.height - self.trackFullHeightDrum + Config.TRACK_SPACING_DIV2, self.trackWidth, self.trackHeightDrum ) ) + + self.pitchPerPixel = float(Config.NUMBER_OF_POSSIBLE_PITCHES-1) / (self.trackHeight - Config.NOTE_HEIGHT) + self.pixelsPerPitch = float(self.trackHeight-Config.NOTE_HEIGHT)/(Config.MAXIMUM_PITCH - Config.MINIMUM_PITCH) #======================================================= # Module Interface @@ -105,7 +162,8 @@ class TrackInterface( gtk.EventBox ): self.pageNoteCount[p] = 0 csnote = noteParams["csnote"][i] note = NoteInterface( self, p, noteParams["track"][i], noteParams["note"][i], \ - csnote["pitch"], csnote["onset"], csnote["duration"], csnote["amplitude"] ) + csnote["pitch"], csnote["onset"], csnote["duration"], csnote["amplitude"], \ + self.image["note"], self.image["noteSelected"], self.trackColors[noteParams["track"][i]] ) while at[p][t] > 0: if self.note[p][t][at[p][t]-1].getStartTick() < csnote["onset"]: break at[p][t] -= 1 @@ -172,11 +230,9 @@ class TrackInterface( gtk.EventBox ): def updateBeatCount( self, beatCount ): self.beatCount = beatCount - # make sure this matches the calculation in size_allocate - self.beatSpacing = (self.fullWidth - Config.BORDER_SIZE_MUL2 + Config.BEAT_LINE_SIZE)/self.beatCount - self.width = self.beatSpacing * self.beatCount + Config.BORDER_SIZE_MUL2 - self.ticksPerPixel = float(self.beatCount * Config.TICKS_PER_BEAT) / (self.width-2*Config.BORDER_SIZE) - self.pixelsPerTick = 1/self.ticksPerPixel + self.pixelsPerTick = self.trackWidth//(self.beatCount*Config.TICKS_PER_BEAT) + self.ticksPerPixel = 1.0/self.pixelsPerTick + self.beatSpacing = self.pixelsPerTick*Config.TICKS_PER_BEAT if self.pageBeatCount[self.curPage] != beatCount: self.pageBeatCount[self.curPage] = beatCount @@ -184,13 +240,13 @@ class TrackInterface( gtk.EventBox ): track = self.note[self.curPage][i] map( lambda note:note.updateTransform( True ), track ) - if self.drawingArea.window != None: + if self.window != None: self.invalidate_rect( 0, 0, self.fullWidth, self.height ) def setPlayhead( self, ticks ): - self.invalidate_rect( self.playheadX, 0, Config.PLAYHEAD_SIZE, self.height ) - self.playheadX = self.ticksToPixels( ticks ) + Config.BORDER_SIZE - self.invalidate_rect( self.playheadX, 0, Config.PLAYHEAD_SIZE, self.height ) + self.invalidate_rect( self.playheadX-Config.PLAYHEAD_SIZE/2, 0, Config.PLAYHEAD_SIZE, self.height ) + self.playheadX = self.ticksToPixels( ticks ) + Config.TRACK_SPACING_DIV2 + self.invalidate_rect( self.playheadX-Config.PLAYHEAD_SIZE/2, 0, Config.PLAYHEAD_SIZE, self.height ) def getSelectedTracks( self ): r = [] @@ -209,38 +265,13 @@ class TrackInterface( gtk.EventBox ): # Event Callbacks def size_allocate( self, widget, allocation ): + self.alloc = allocation width = allocation.width height = allocation.height - - self.drawingArea.set_size_request( width, height ) - - self.trackHeight = (height - (Config.NUMBER_OF_TRACKS-1)*Config.TRACK_SPACING) / Config.NUMBER_OF_TRACKS - self.height = self.trackHeight*Config.NUMBER_OF_TRACKS + Config.TRACK_SPACING*(Config.NUMBER_OF_TRACKS-1) - self.trackLimits = [] - self.trackOrigin = [] - for i in range(Config.NUMBER_OF_TRACKS): - start = i*(self.trackHeight+Config.TRACK_SPACING) - self.trackLimits.insert( i, (start,start+self.trackHeight) ) - self.trackOrigin.insert( i, (Config.BORDER_SIZE,start+Config.BORDER_SIZE) ) - - self.fullWidth = width - 2 # cut off 2 pixels cause otherwise we try to draw on an area that gets cut off!? - - # make sure this matches the calculations in updateBeatCount - self.beatSpacing = (self.fullWidth - Config.BORDER_SIZE_MUL2 + Config.BEAT_LINE_SIZE)/self.beatCount - self.width = self.beatSpacing * self.beatCount + Config.BORDER_SIZE_MUL2 - self.ticksPerPixel = float(self.beatCount * Config.TICKS_PER_BEAT) / (self.width-2*Config.BORDER_SIZE) - self.pixelsPerTick = 1/self.ticksPerPixel - - self.pitchPerPixel = float(Config.NUMBER_OF_POSSIBLE_PITCHES-1) / (self.trackHeight-2*Config.BORDER_SIZE-Config.NOTE_HEIGHT) - self.pixelsPerPitch = float(self.trackHeight-2*Config.BORDER_SIZE-Config.NOTE_HEIGHT)/(Config.MAXIMUM_PITCH - Config.MINIMUM_PITCH) - - # this could potentially take a loooong time, make sure they don't resize the window very often - for page in self.note: - for i in range(Config.NUMBER_OF_TRACKS): - track = self.note[page][i] - map( lambda note:note.updateTransform( False ), track ) - - if self.drawingArea.window != None: + + self.drawingArea.set_size_request( width, height ) + + if self.window != None: self.invalidate_rect( 0, 0, width, height ) def handleButtonPress( self, widget, event ): @@ -574,7 +605,7 @@ class TrackInterface( gtk.EventBox ): width = max( self.marqueeRect[0][0] + self.marqueeRect[1][0], oldEndX ) - x y = min( self.marqueeRect[0][1], oldY ) height = max( self.marqueeRect[0][1] + self.marqueeRect[1][1], oldEndY ) - y - self.invalidate_rect( x-1, y-1, width+2, height+2 ) # increase by 1 to handle switching quadrants + self.invalidate_rect( x-1, y-1, width+2, height+2 ) def doneMarquee( self, event ): if self.marqueeLoc: @@ -605,14 +636,15 @@ class TrackInterface( gtk.EventBox ): self.invalidate_rect( self.marqueeRect[0][0]-1, self.marqueeRect[0][1]-1, self.marqueeRect[1][0]+2, self.marqueeRect[1][1]+2 ) def updatePlayhead( self, event ): - x = min( self.width - Config.BORDER_SIZE_MUL2 - self.pixelsPerTick, max( Config.BORDER_SIZE, event.x ) ) + x = min( self.trackWidth - self.pixelsPerTick, max( Config.TRACK_SPACING_DIV2, event.x ) ) self.setPlayhead( self.pixelsToTicks( x ) ) def donePlayhead( self, event ): - x = min( self.width - Config.BORDER_SIZE_MUL2, max( Config.BORDER_SIZE, event.x ) ) + x = min( self.trackWidth - self.pixelsPerTick, max( Config.TRACK_SPACING_DIV2, event.x ) ) ticks = self.pixelsToTicks( x ) - print "set playhead to %d ticks" % (ticks) + print "set playhead to %d ticks" % (ticks) + self.doneCurrentAction() def updateTooltip( self, event ): @@ -652,75 +684,69 @@ class TrackInterface( gtk.EventBox ): #======================================================= # Drawing - def draw( self, drawingArea, event ): + def expose( self, DA, event ): TP.ProfileBegin( "TrackInterface::draw" ) startX = event.area.x startY = event.area.y stopX = event.area.x + event.area.width stopY = event.area.y + event.area.height - - context = drawingArea.window.cairo_create() - context.set_antialias(0) # I don't know what to set this to to turn it off, and it doesn't seem to work anyway!? - - for i in range( Config.NUMBER_OF_TRACKS): + + #print "%d %d %d %d" % (startX,startY,stopX,stopY) + + self.gc.set_line_attributes( Config.BEAT_LINE_SIZE, gtk.gdk.LINE_ON_OFF_DASH, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER ) + # regular tracks + for i in range( self.drumIndex ): if startY > self.trackLimits[i][1]: continue if stopY < self.trackLimits[i][0]: break - if False: - context.set_line_width( Config.BORDER_SIZE ) - - context.move_to( Config.BORDER_SIZE_DIV2, self.trackLimits[i][0] + Config.BORDER_SIZE_DIV2 ) - context.rel_line_to( self.width - Config.BORDER_SIZE, 0 ) - context.rel_line_to( 0, self.trackHeight - Config.BORDER_SIZE ) - context.rel_line_to( -self.width + Config.BORDER_SIZE, 0 ) - context.close_path() - - #draw background - context.set_source_rgb( 0.75, 0.75, 0.75 ) - context.fill_preserve() - + # draw background + if self.trackSelected[i]: + DA.window.draw_drawable( self.gc, self.image["trackBGSelected"], 0, 0, 0, self.trackLimits[i][0], self.trackFullWidth, self.trackFullHeight ) else: - context.rectangle(Config.BORDER_SIZE_DIV2, self.trackLimits[i][0] + Config.BORDER_SIZE_DIV2 , self.width, self.height) - context.set_source_rgb( 0.75, 0.75, 0.75 ) - context.fill() - - # draw border - if self.trackSelected[i]: context.set_source_rgb( 1, 1, 1 ) - else: context.set_source_rgb( 0, 0, 0 ) - context.stroke() + DA.window.draw_drawable( self.gc, self.image["trackBG"], 0, 0, 0, self.trackLimits[i][0], self.trackFullWidth, self.trackFullHeight ) # draw beat lines - context.set_line_width( Config.BEAT_LINE_SIZE ) - beatStart = Config.BORDER_SIZE + Config.BEAT_LINE_SIZE_DIV2 - context.set_source_rgb( 0.4, 0.4, 0.4 ) + self.gc.foreground = self.beatColor + beatStart = Config.TRACK_SPACING_DIV2 for j in range(1,self.beatCount): - context.move_to( beatStart + j*self.beatSpacing, self.trackLimits[i][0] + Config.BORDER_SIZE ) - context.rel_line_to( 0, self.trackHeight - Config.BORDER_SIZE_MUL2 ) - context.stroke() - + x = beatStart + j*self.beatSpacing + DA.window.draw_line( self.gc, x, self.trackRect[i].y, x, self.trackRect[i].y+self.trackRect[i].height ) + # draw notes notes = self.note[self.curPage][i] for n in range(len(notes)): - if not notes[n].draw( context, startX, stopX ): break + if not notes[n].draw( DA.window, self.gc, startX, stopX ): break + + # drum track + if stopY > self.trackLimits[self.drumIndex][0]: + # draw background + if self.trackSelected[self.drumIndex]: + DA.window.draw_drawable( self.gc, self.image["trackBGDrumSelected"], 0, 0, 0, self.trackLimits[self.drumIndex][0], self.trackFullWidth, self.trackFullHeightDrum ) + else: + DA.window.draw_drawable( self.gc, self.image["trackBGDrum"], 0, 0, 0, self.trackLimits[self.drumIndex][0], self.trackFullWidth, self.trackFullHeightDrum ) + + # draw beat lines + self.gc.foreground = self.beatColor + beatStart = Config.TRACK_SPACING_DIV2 + for j in range(1,self.beatCount): + x = beatStart + j*self.beatSpacing + DA.window.draw_line( self.gc, x, self.trackRect[self.drumIndex].y, x, self.trackRect[self.drumIndex].y+self.trackRect[self.drumIndex].height ) + # draw notes + notes = self.note[self.curPage][self.drumIndex] + for n in range(len(notes)): + if not notes[n].draw( DA.window, self.gc, startX, stopX ): break + # draw playhead - context.set_line_width( Config.PLAYHEAD_SIZE ) - context.move_to( self.playheadX + Config.PLAYHEAD_SIZE_DIV2, 0 ) - # do some fancy shit here to grey out muted tracks!? - context.rel_line_to( 0, self.height ) - context.set_source_rgb( 0, 0, 0 ) - context.stroke() - + self.gc.set_line_attributes( Config.PLAYHEAD_SIZE, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER ) + self.gc.foreground = self.playheadColor + DA.window.draw_line( self.gc, self.playheadX, startY, self.playheadX, stopY ) + if self.marqueeLoc: # draw the selection rect - context.set_line_width( 1 ) - context.move_to( self.marqueeRect[0][0] + 0.5, self.marqueeRect[0][1] + 0.5 ) - context.rel_line_to( self.marqueeRect[1][0] - 1, 0 ) - context.rel_line_to( 0, self.marqueeRect[1][1] - 1 ) - context.rel_line_to( -self.marqueeRect[1][0] + 1, 0 ) - context.close_path() - context.set_source_rgb( 1, 1, 1 ) - context.stroke() + self.gc.set_line_attributes( Config.MARQUEE_SIZE, gtk.gdk.LINE_ON_OFF_DASH, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER ) + self.gc.foreground = self.marqueeColor + DA.window.draw_rectangle( self.gc, False, self.marqueeRect[0][0], self.marqueeRect[0][1], self.marqueeRect[1][0], self.marqueeRect[1][1] ) self.drawingAreaDirty = False @@ -736,7 +762,7 @@ class TrackInterface( gtk.EventBox ): #self.queue_draw() def getTrackOrigin( self, track ): - return self.trackOrigin[track] + return ( self.trackRect[track].x, self.trackRect[track].y ) def ticksToPixels( self, ticks ): return int(round( ticks * self.pixelsPerTick )) diff --git a/Resources/Images/note.png b/Resources/Images/note.png Binary files differnew file mode 100755 index 0000000..03947e4 --- /dev/null +++ b/Resources/Images/note.png diff --git a/Resources/Images/noteSelected.png b/Resources/Images/noteSelected.png Binary files differnew file mode 100755 index 0000000..f253ff0 --- /dev/null +++ b/Resources/Images/noteSelected.png diff --git a/Resources/Images/trackBG.png b/Resources/Images/trackBG.png Binary files differnew file mode 100755 index 0000000..b875dda --- /dev/null +++ b/Resources/Images/trackBG.png diff --git a/Resources/Images/trackBGDrum.png b/Resources/Images/trackBGDrum.png Binary files differnew file mode 100755 index 0000000..aeb73b2 --- /dev/null +++ b/Resources/Images/trackBGDrum.png diff --git a/Resources/Images/trackBGDrumSelected.png b/Resources/Images/trackBGDrumSelected.png Binary files differnew file mode 100755 index 0000000..06e1871 --- /dev/null +++ b/Resources/Images/trackBGDrumSelected.png diff --git a/Resources/Images/trackBGSelected.png b/Resources/Images/trackBGSelected.png Binary files differnew file mode 100755 index 0000000..d1bf236 --- /dev/null +++ b/Resources/Images/trackBGSelected.png diff --git a/Util/Sound.py b/Util/Sound.py new file mode 100644 index 0000000..be00cb5 --- /dev/null +++ b/Util/Sound.py @@ -0,0 +1,276 @@ +import csnd +import os +import socket +import select +import sys +import threading +import time +import bisect + +from sugar import env +import Config + +from Util.CSoundNote import CSoundNote #maybe not actually used, but dependence is there. All notes are assumed to be CSoundNotes +from Generation.GenerationConstants import GenerationConstants + +class Sound: + #PRIVATE + DRIFT = 0.01 #careful about changing this... coordinate with instrument 5777 + def loop_work(self, sleeptime): + def next( ) : + time_time = time.time() + #tickhorizon is tick where we'll be after range_sec + tickhorizon = self.getTick( self.range_sec + time_time, False ) + time0_time = self.time0 - self.time_start + self.DRIFT + + if tickhorizon < 0 : return [] + if len(self.notes) == 0 : return [] + + def cache_cmd(secs_per_tick, amplitude, pitch, inst, trackId, duration, tied, fullDuration, overlap, attack, decay, reverbSend, filterType, filterCutoff, pan ): + if inst[0:4] == 'drum': + if pitch in GenerationConstants.DRUMPITCH: + key = GenerationConstants.DRUMPITCH[ pitch ] + else: + key = pitch + + if inst == 'drum1kit': + inst = Config.DRUM1INSTRUMENTS[ key ] + if inst == 'drum2kit': + inst = Config.DRUM2INSTRUMENTS[ key ] + if inst == 'drum3kit': + inst = Config.DRUM3INSTRUMENTS[ key ] + pitch = 1 + + else: + pitch = GenerationConstants.TRANSPOSE[ pitch - 24 ] + + # condition for tied notes + if Config.INSTRUMENTS[ inst ].csoundInstrumentId == 101 and tied and fullDuration: + duration= -1.0 + # condition for overlaped notes + if Config.INSTRUMENTS[ inst ].csoundInstrumentId == 102 and overlap: + duration += 1.0 + + attack = max( 0.002, duration * attack) + decay = max( 0.002, duration * decay) + + rval = Config.PLAY_NOTE_COMMAND_MINUS_DELAY % \ + ( Config.INSTRUMENTS[ inst ].csoundInstrumentId, + trackId, + '%f', #delay, + duration, + pitch, + reverbSend, + amplitude, + pan, + Config.INSTRUMENT_TABLE_OFFSET + Config.INSTRUMENTS[ inst ].instrumentId, + attack, + decay, + filterType, filterCutoff ) + return rval + + def getText(i, secs_per_tick, time_offset): + (onset,note,cache,z) = self.notes[i] + if cache == '' or note.nchanges != z : + self.notes[i] = \ + ( + onset, + note, + cache_cmd( + secs_per_tick, + note.amplitude, # * track-level mixer rate + note.pitch, + note.instrumentFlag, + note.trackId, + note.duration * self.secs_per_tick, + note.tied, + note.fullDuration, + note.overlap, + note.attack, + note.decay, + note.reverbSend, + note.filterType, + note.filterCutoff, + note.pan), + note.nchanges + ) + rval = self.notes[i][2] % float(onset * self.secs_per_tick + time_offset) + return rval + + prev_secs = (self.loops * self.duration) * self.secs_per_tick + rval = [] + while self.notes[self.hIdx][0] + self.loops * self.duration < tickhorizon: + rval.append ( getText(self.hIdx, self.secs_per_tick, prev_secs + time0_time ) ) + self.hIdx += 1 + if self.hIdx == len(self.notes): + self.hIdx = 0 + self.loops += 1 + prev_secs += self.duration * self.secs_per_tick + + return rval + + #thread.start_new_thread( testtimer, (0,) ) + m = 0.0 + while self.thread_continue: + t0 = time.time() + time.sleep(sleeptime) + t1 = time.time() + if t1 - t0 > 2.0 * sleeptime : + print 'critical lagginess: ', t1 - t0 + if m < t1 - t0: + m = t1 - t0 + print t1, ' timer max = ', m + cmds = self.next() + for c in cmds: + self.perf.InputMessage( '' ) + + def __init__(self, orc, range_sec, ticks_per_sec ): + self.orc = orc + self.up = False + self.csound = csnd.Csound() + + self.ticks_per_sec = ticks_per_sec # ticks last this long + self.secs_per_tick = 1.0 / ticks_per_sec # precomputed inverse + self.range_sec = range_sec # notes are checked-for, this many seconds in advance + + self.duration = 0 # number of ticks in playback loop + self.loops = 0 # number of elapsed loops + self.notes = [] # sorted list of (onset, noteptr, cache) + + self.time0 = time.time() + 1000000 # the real time at which tick == 0 (sometimes retro-active) + self.thread_continue = 1 + self.thread = thread.start_new_thread( loop_work, (self,0.040) ) + + def uninit(self): + self.thread_continue = 0 + self.thread.join() + if self.up : self.lower() + + def micRecording( self, table ): + mess = Config.MIC_RECORDING_COMMAND % table + self.sendText( mess ) + + def load_mic_instrument( self, inst ): + home_path = env.get_profile_path() + Config.PREF_DIR + fileName = home_path + '/' + inst + instrumentId = Config.INSTRUMENT_TABLE_OFFSET + int(fileName[-1]) + 6 + mess = Config.LOAD_INSTRUMENT_COMMAND % ( instrumentId, fileName ) + self.sendText( mess ) + + def startTime(self): + if not self.up : + debug_print (1, "ERROR: Sound::startTime, performance thread isn't up yet.") + return + self.perf.InputMessage('i 5999 0.0 60000000') + self.time_start = time.time() + # if a note event is sent to csound before or simultaneous to this one, then it will not play correctly. + # thus we sleep right here, to (ideally) let csound pick up the message. + # NB: match this to the constant in the instrument 5777 of the csound orcestra + time.sleep(0.1) + + def load_instruments( self ): + home_path = env.get_profile_path() + Config.PREF_DIR + for instrumentSoundFile in Config.INSTRUMENTS.keys(): + if instrumentSoundFile[0:3] == 'mic' or instrumentSoundFile[0:3] == 'lab': + fileName = home_path + '/' + instrumentSoundFile + else: + fileName = Config.SOUNDS_DIR + "/" + instrumentSoundFile + instrumentId = Config.INSTRUMENT_TABLE_OFFSET + Config.INSTRUMENTS[ instrumentSoundFile ].instrumentId + mess = Config.LOAD_INSTRUMENT_COMMAND % ( instrumentId, fileName ) + self.sendText( mess ) + + def raise( self ): + if self.up : + debug_print(3, 'Sound::raise() already up.') + return + self.up = True + self.perf = csnd.CsoundPerformanceThread(self.csound) + self.csound.Compile( self.orc ) + self.perf.Play() + self.load_instruments() + debug_print(5, 'Sound::raise succeeded') + + def lower(self): + if not self.up : + debug_print(3, 'Sound::lower() already down.') + return + self.up = False + self.sendText( Config.UNLOAD_TABLES_COMMAND ) + self.perf.Stop() + rval = self.perf.Join() + self.csound.Reset() + debug_print(5, 'Sound::lower() succeeded') + + def setMasterVolume(self, volume): + self.csound.SetChannel('masterVolume',volume ) + + def inputMessage(self, txt): + self.perf.InputMessage(txt) + + def loop_setTick( self, tick ): + time_time = time.time() + self.time0 = time_time - tick * self.secs_per_tick + self.loops = tick // self.duration + self.hIdx = bisect.bisect_left(self.notes, tick - self.duration * self.loops ) + + def loop_setRate( self, ticks_per_sec): + if ticks_per_sec != self.ticks_per_sec: + secs_per_tick = 1.0 / ticks_per_sec + + time_time = time.time() + curtick = self.getTick( time_time, False ) + curticktime = curtick * self.secs_per_tick + self.time0 + + self.ticks_per_sec = ticks_per_sec + self.secs_per_tick = secs_per_tick + self.time0 = curticktime - curtick * secs_per_tick + self.notes = [ (o,n,'',z) for (o,n,c,z) in self.notes ] #clear cache + self.loops = 0 + + def loop_setDuration( self, duration ): + self.time0 += self.loops * self.duration * self.secs_per_tick + self.loops = 0 + self.duration = duration + + def loop_getTick(self, t, domod): #t is for time + if domod : + return ( int( ( t - self.time0 ) * self.ticks_per_sec ) ) % self.duration + else : + return ( int( ( t - self.time0 ) * self.ticks_per_sec ) ) + + def loop_insert( self, notes): + def insertMany(): + self.notes += [ ( notes[i][0], notes[i][1], '', 0 ) for i in xrange(len(notes)) ] + self.notes.sort() + def insertFew(): + for i in xrange(len(notes)): + t = (notes[i][0], notes[i][1],'',0) + l = bisect.bisect_left(self.notes, t ) + self.notes.insert(l, t) + + if len(notes) >= 1: + insertMany() + else: + insertFew() + self.hIdx = bisect.bisect_left(self.notes, self.getTick(self.range_sec + time.time(), True)) + + def loop_remove(self, note): + def removeFew(): + i = 0 + while i < len(self.notes): + if self.notes[i][1] in note: + del self.notes[i] + else: + i += 1 + + def removeMany(): + self.notes = [t for t in self.notes if t[1] not in note] + + if len(idset) >= 0: #just guessing here, should do some timing tests to see if this is good or no + removeMany() + else: + removeFew() + self.hIdx = bisect.bisect_left(self.notes, self.getTick(self.range_sec + time.time(), True)) + + def loop_clear(self): + self.notes = [] diff --git a/scripts/olpc_get_stuff.sh b/scripts/olpc_get_stuff.sh index ebbd292..9751900 100644..100755 --- a/scripts/olpc_get_stuff.sh +++ b/scripts/olpc_get_stuff.sh @@ -12,10 +12,10 @@ echo 'export GIT_AUTHOR_NAME GIT_COMMITTER_NAME in .bashrc' echo 'edit olpc's .xinitrc file to change the window-manager' -read USER - -mkdir cvs -cd cvs -git-clone "git+ssh://$USER@dev.laptop.org/git/projects/tamtam" tamtam +echo 'this might help you get your git repo back up:' +echo 'read USER' +echo 'mkdir cvs' +echo 'cd cvs' +echo 'git-clone "git+ssh://$USER@dev.laptop.org/git/projects/tamtam" tamtam' |