■
- 音符に尻尾がついた
- 音符を右クリックすると長さが変更されるように(4→2→1→4…)
- なんとなく4分音符を0.25秒に
一応音楽っぽいものが出るようになった。画像は「むすんでひらいて」
まだあまりにも汚いプログラムなんでもう少し可愛くしたい。
#!/usr/bin/env python import Tkinter import math import sndPlay class scorePlayer: def __init__(self): self.width = 800 self.height = 200 self.window = Tkinter.Tk() self.canvas = Tkinter.Canvas(self.window,bg='white', width=self.width,height=self.height) self.canvas.bind("<Motion>",self.motionCanvas) self.canvas.bind("<ButtonPress-1>",self.press1Canvas) self.canvas.bind("<ButtonPress-3>",self.press3Canvas) freqMap = [{'inc':3,'color':'white'}, # C {'inc':5,'color':'white'}, # D {'inc':7,'color':'black'}, # E {'inc':8,'color':'white'}, # F {'inc':10,'color':'black'}, # G {'inc':12,'color':'white'}, # A {'inc':14,'color':'black'}, # B {'inc':15,'color':'white'}, # C {'inc':17,'color':'black'}, # D {'inc':19,'color':'white'}, # E {'inc':20,'color':'black'}, # F {'inc':22,'color':'white'}, # G {'inc':24,'color':'white'}, # A ] inc = math.pow(2,1.0/12) A = 440 self.toneMap = [{'index':ii,'freq':math.pow(inc,freqMap[ii]['inc'])*A, 'color':freqMap[ii]['color']} for ii in range(len(freqMap))] self.toneMap.reverse() self.notes = [] self.canvas.pack() self.currentNote = None self.mouseOverNote = None self.xStart = 40 self.currentX = 0 self.xInterval = 30 self.scoreYInterval = 10 self.noteWidth,self.noteHeight = 15,8 self.paint() self.playButton = Tkinter.Button(self.window,text="play", command=self.play) self.clearButton = Tkinter.Button(self.window,text='clear', command=self.clear) self.playButton.pack(side=Tkinter.RIGHT) self.clearButton.pack(side=Tkinter.RIGHT) self.window.mainloop() def clear(self): for note in self.notes: self.canvas.delete(note['index']['bar']) self.canvas.delete(note['index']['body']) self.notes = [] self.currentX = 0 def itemConfig(self,id,arg): print id,arg self.canvas.itemconfigure(id,**arg) def play(self): s = sndPlay.sndPlay() s.A = 440 for note in self.notes: print note s.addWave(note['tone']['freq'],1.0/note['length']) s.addWave(0,0.1) s.closeFile() def convertYtoTone(self,y): interval = self.scoreYInterval / 2 for tone in self.toneMap: jj = tone['y'] if jj-interval < y < jj+interval: return tone return None def repaintNote(self,note): barId,bodyId = note['index']['bar'],note['index']['body'] length = note['length'] if length==1: self.canvas.itemconfigure(barId,fill='white') self.canvas.itemconfigure(bodyId,fill='white',outline='black') elif length==2: self.canvas.itemconfigure(barId,fill='black') self.canvas.itemconfigure(bodyId,fill='white',outline='black') elif length==4: self.canvas.itemconfigure(barId,fill='black') self.canvas.itemconfigure(bodyId,fill='black',outline='black') def press3Canvas(self,event): x,y = event.x,event.y note = self.findNote(x,y) if note==None: return print note length = note['length'] if length > 1: length = length / 2 else: length = 4 note['length'] = length self.repaintNote(note) def press1Canvas(self,event): x = event.x y = event.y note=self.findNote(x,y) if note!=None: print note else: width,height = self.noteWidth,self.noteHeight tone = self.convertYtoTone(event.y) if tone==None: return y = tone['y'] x = self.currentX*self.xInterval+self.xStart barHeight = 30 index = {'body':self.canvas.create_oval(x-width/2,y-height/2, x+width/2,y+height/2, fill='black', width=2), 'bar':self.canvas.create_line(x+width/2,y, x+width/2,y-barHeight, width=1)} self.currentX = self.currentX + 1 self.notes.append({'tone':tone,'index':index,'length':4}) def findNote(self,x,y): for note in self.notes: barId = note['index']['bar'] bodyId = note['index']['body'] sx,sy,ex,ey = self.canvas.coords(bodyId) if sx <= x <= ex and sy <= y <= ey: return note def motionCanvas(self,event): x = event.x y = event.y note=self.findNote(x,y) if note!=None: if self.currentNote!=None: self.canvas.delete(self.currentNote) self.currentNote = None bodyId = note['index']['body'] barId = note['index']['bar'] self.canvas.itemconfigure(bodyId,fill='red',outline='red') self.canvas.itemconfigure(barId,fill='red') self.mouseOverNote = note else: if self.mouseOverNote!=None: self.repaintNote(self.mouseOverNote) width,height = self.noteWidth,self.noteHeight tone = self.convertYtoTone(event.y) if tone==None: return y = tone['y'] if self.currentNote == None: self.currentNote = self.canvas.create_oval(x-width/2,y-height/2, x+width/2,y+height/2, outline='gray', fill='gray', width=2) else: self.canvas.coords(self.currentNote, x-width/2,y-height/2, x+width/2,y+height/2) def paint(self): xMargin = 30 yMargin = 30 scoreYInterval = self.scoreYInterval for ii in range(len(self.toneMap)): sx = xMargin ex = self.width - xMargin sy = ey = yMargin + scoreYInterval/2*ii self.canvas.create_line(sx,sy,ex,ey,fill=self.toneMap[ii]['color'],width=1) self.toneMap[ii]['y'] = sy if __name__ == '__main__': scorePlayer()