python编写的midi制作软件

发布时间:2018-09-13 12:48:59

心之所向,所向披靡

Python编写的Mid音频制作软件

源代码如下:

#Midi.py:

#This file can be used to simply turn MidiTxt file to Mid file.

#Author:loupen

#Date:2010-7-20

#If you want to use it, you must write the MidiTxt file by some rules.

#Read the document to learn more.

from struct import *

#Three global variables

TrackBegin=[]

TrackEnd=[]

ToneFore=1

#write the MidiHeader

def MidiHeader(buffer):

buffer.write(pack('ccccBBBB','M','T','h','d',0,0,0,6))

def msg(buffer,tracks,deltatime):

if deltatime>0xff:

buffer.write(pack('BBBBBB',0,1,0,tracks,deltatime>>8,deltatime&0xff))

else:

buffer.write(pack('BBBBBB',0,1,0,tracks,0,deltatime))

return buffer.tell()-3

#write the header and tail of tracks

def TrackHeader(buffer,list):

buffer.write(pack('cccc','M','T','r','k'))

list.append(buffer.tell())

buffer.write(pack('i',0))

def TrackTail(buffer,list):

buffer.write(pack('BBBB',0,0xff,0x2f,0))

list.append(buffer.tell())

#Set the pulse , instrument and controller

def SetSpeed(buffer,time):

time=60.0/int(time)

time=int(time*(10**6))

buffer.write(pack('BBBBBBB',0,0xff,0x51,3,time>>16,(time&0xff00)>>8,time&0xff))

return 1

#The words , FenZi and FenMu , are from Chinese . ~O~

def SetPulse(buffer,FenZi,FenMu):

FenZi=int(FenZi)

FenMu=int(FenMu)

if FenMu==2:

FenMu=1

elif FenMu==4:

FenMu=2

elif FenMu==8:

FenMu=3

else: return 0

buffer.write(pack('BBBBBBBB',0,0xff,0x58,4,int(FenZi),int(FenMu),0x18,0x08))

return 1

def SetTone(buffer):

buffer.write(pack('BBBBBB',0,0xff,0x59,2,0,0))

return 1

def SetNumOrder(buffer,time):

buffer.write(pack('BBBB',time>>24,(time&0xff0000)>>16,(time&0xff00)>>8,time&0xff))

def SetTrackNum(buffer,ad,n):

buffer.seek(ad)

buffer.write(pack('B',n+1))

def SetInstrument(buffer,trackNum,ITNum):

trackNum=int(trackNum)

trackNum+=0xc0

buffer.write(pack('BBB',0,trackNum,ITNum))

def SetController(buffer,trackNum,CtrNum):

trackNum=int(trackNum)

trackNum+=0xb0

buffer.write(pack('BBBB',0,trackNum,11,CtrNum))

buffer.write(pack('BBB',0,0xa,0x40))

def SetVolume(buffer,trackNum,S):

trackNum=int(trackNum)

trackNum+=0xb0

if S=='H':

buffer.write(pack('BBBB',0,trackNum,7,0x7f))

buffer.write(pack('BBB',0,0xa,0x40))

if S=='L':

buffer.write(pack('BBBB',0,trackNum,7,80))

buffer.write(pack('BBB',0,0xa,0x40))

def SetChanYin(buffer,trackNum):

trackNum=int(trackNum)

trackNum+=0xb0

buffer.write(pack('BBBB',0,trackNum,1,127))

#imitate the function of buffer in C

def readNext(buffer):

while True:

a=buffer.read(1)

if a in [' ','\n']:

pass

else: return a

#def seekFore(buffer,offset):

# buffer.seek(buffer.tell()-offset)

#Use the following two functions to deal with the events

def liftup(buffer,time,note):

time=int(time)

if time>=128:

buffer.write(pack('BBBB',0x80|(time>>7),0x7f&time,note,0))

else:

buffer.write(pack('BBB',time,note,0))

def pressdown(buffer,num,dict,mark,note,force):

global ToneFore

a=dict[note]+(5+mark)*12

if ToneFore==1:

num+=0x90

buffer.write(pack('BBBB',0,num,a,force))

else:

buffer.write(pack('BBB',0,a,force))

ToneFore=a

def main(lp):

track=1;deltatime=120

speed='';temp=0

begin=0;mark=0;time=deltatime

TrackNum=[0,1,2,3];ITNum=lp;CtrNum=0x7f

dict={'0':0,'1':0,'2':2,'3':4,'4':5,'5':7,'6':9,'7':11}

pTxt=open(r'.\1.txt')

s=".\\%d.mid" %lp[0]

pMid=open(s,'wb')

if pTxt.read(6)!="":

print "This is not MidiTxt file!"

pMid.close()

pTxt.close()

return 0

while True:

if pTxt.read(1)=='|':

FenMu=pTxt.read(1)

pTxt.seek(pTxt.tell()-3)

FenZi=pTxt.read(1)

n=0

while n<8:

if readNext(pTxt)=='<':break

n+=1

if n==8:

print "This is not MidiTxt file!"

pMid.close()

pTxt.close()

return 0

break

n=0

a=readNext(pTxt)

while a!='>':

speed+=a

a=readNext(pTxt)

MidiHeader(pMid)

track=msg(pMid,0,deltatime)

TrackHeader(pMid,TrackBegin)

SetPulse(pMid,FenZi,FenMu)

SetTone(pMid)

SetSpeed(pMid,speed)

TrackTail(pMid,TrackEnd)

pMid.seek(TrackBegin[0])

SetNumOrder(pMid,TrackEnd[0]-TrackBegin[0]-4)

pMid.seek(TrackEnd[0])

a=readNext(pTxt)

while a=='[':

pTxt.readline()

TrackHeader(pMid,TrackBegin)

SetInstrument(pMid,TrackNum[n],ITNum[n])

SetController(pMid,TrackNum[n],CtrNum)

a=readNext(pTxt)

n+=1

while True:

if a=='|':

a=readNext(pTxt)

if a=='|':

a=readNext(pTxt)

if a in ['[','']:

global ToneFore

ToneFore=-1;break

elif a=='\'':

mark+=1

a=readNext(pTxt)

elif a=='.':

if begin==0: mark-=1

elif begin==1:

time*=3.0/2

liftup(pMid,time,ToneFore)

begin=0

elif begin==2:

a=pTxt.read(1)

if a in [' ','|']:

if a=='|':

print "\'|\' is too close to Number !\n",pTxt.tell(),pTxt.read(1)

time*=3.0/2

time+=temp

liftup(pMid,time,ToneFore)

begin=0;temp=0

mark=0

else:continue

a=readNext(pTxt)

elif a=='Y':

time=deltatime/2

a=pTxt.read(1)

if a in [' ','|']:

if a=='|':

print "\'|\' is too close to Number !\n",pTxt.tell(),pTxt.read(1)

if begin==2:time+=temp

liftup(pMid,time,ToneFore)

begin=0;temp=0

mark=0

a=readNext(pTxt)

elif a=='E':

time=deltatime/4

a=pTxt.read(1)

if a in [' ','|']:

if a=='|':

print "\'|\' is too close to Number !\n",pTxt.tell(),pTxt.read(1)

if begin==2:time+=temp

liftup(pMid,time,ToneFore)

begin=0;temp=0

mark=0

a=readNext(pTxt)

elif a=='S':

time=deltatime/8

a=pTxt.read(1)

if a in [' ','|']:

if a=='|':

print "\'|\' is too close to Number !\n",pTxt.tell(),pTxt.read(1)

if begin==2:time+=temp

liftup(pMid,time,ToneFore)

begin=0;temp=0

mark=0

a=readNext(pTxt)

elif '7'>=a>='0':

if begin==0:

if a=='0': force=0

else: force=100

pressdown(pMid,TrackNum[n-1],dict,mark,a,force)

time=deltatime

mark=0;begin=1

a=pTxt.read(1)

if a in [' ','|']:

if a=='|':

print "\'|\' is too close to Number !\n",pTxt.tell(),pTxt.read(1)

liftup(pMid,time,ToneFore)

begin=0

a=readNext(pTxt)

elif begin==2:

time=deltatime

a=pTxt.read(1)

if a in [' ','|']:

if a=='|':

print "\'|\' is too close to Number !\n",pTxt.tell(),pTxt.read(1)

time+=temp

liftup(pMid,time,ToneFore)

begin=0;temp=0

mark=0

a=readNext(pTxt)

elif a=='^':

begin=2

temp+=time

a=readNext(pTxt)

elif a=='-':

a=pTxt.read(1)

if a in [' ','|']:

if a=='|':

print "\'|\' is too close to Number !\n",pTxt.tell(),pTxt.read(1)

time+=temp

liftup(pMid,time,ToneFore)

begin=0;temp=0

mark=0

a=readNext(pTxt)

elif a=='*':

SetVolume(pMid,TrackNum[n-1],'H')

ToneFore=1

a=readNext(pTxt)

elif a==',':

SetVolume(pMid,TrackNum[n-1],'L')

ToneFore=1

a=readNext(pTxt)

elif a=='W':

SetChanYin(pMid,TrackNum[n-1])

ToneFore=1

a=readNext(pTxt)

else:

print "This is not MidiTxt file!"

pMid.close()

pTxt.close()

return 0

TrackTail(pMid,TrackEnd)

pMid.seek(TrackBegin[n])

SetNumOrder(pMid,TrackEnd[n]-TrackBegin[n]-4)

pMid.seek(TrackEnd[n])

SetTrackNum(pMid,track,n)

pMid.close()

pTxt.close()

print "\nOK!---LOUPEN"

以上文件存为midi.py

#test.py:

import midi

i=1

z=[]

j=int(input("How many tracks?"))

while i<=j:

tmp=input("The Instrument number is:")

z.append(int(tmp))

i+=1

midi.main(z)

以上文件存为test.py

以下为mid文本范例【赛马】:

<2|4> <120>

[1]

|| 6. 3E 5E | 6. 3E 5E | 6. 3E 5E | 6. 3E 5E | 6E 5E 3E 5E 6E 5E 3E 5E | 6E 5E 3E 5E 6E 5E 3E 5E | 6Y 5E 6E 6Y 5E 6E |

6Y 5E 6E 6Y 5E 6E | .6Y 3Y 1Y .6Y | 3Y 6Y 5Y 3Y | 2E 3E 2E 1E 2E 3E 2E 1E | 2E 3E 2E 1E 2E 3E 2E 1E | .6Y 3Y 1Y .6Y | 3Y 6Y 5Y 3Y |

2E 3E 2E 1E 2E 3E 2E 1E | 2E 3E 2E 1E 2E 3E 2E 1E | 2. .6E 1E | 2. .6E 1E | 2. .6E 1E | 2. .6E 1E | 2E 3E 2E 1E 2E 3E 2E 1E |

2E 3E 2E 1E 2E 3E 2E 1E | 2Y 1E 2E 2Y 1E 2E | 2Y 1E 2E 2Y 1E 2E | .6 6 | 5 3 | 2 5 | 3 1 |

.6 6 | 5 3 | 2 5 | 3 1 | .6. 1E 2E | .6. 1E 2E | .6. 1E 2E | .6. 1E 2E | .6E 2E 1E 2E .6E 2E 1E 2E | .6E 2E 1E 2E .6E 2E 1E 2E |

.6 .6Y .6Y | .6^ .6 | 3 6Y. '1E | 5. 3Y | 5Y 6Y '1Y. '3E | 6^ 6 | 3 6Y. '1E | 5 5Y 3Y | 2Y 3Y 6Y 5Y | 3^ 3 | 5 6Y. '1E |

1. .6Y | 2Y 3Y 6Y 5Y | 3 3Y 2Y | 1Y. 2E 3Y 5Y | 6 .6 | 2Y 3Y 1Y. 3E | .6^ .6 | 3Y 3E 3E 6Y '1Y | 5Y 5E 5E 5Y 3Y |

5Y 5E 6E '1Y '2E '1E | 6Y 6E 6E 6Y .6Y | 3Y 3E 3E 6Y '1Y | 5Y 5E 5E 5Y 3Y | 2Y 2E 3E 6Y 5Y | 3Y 3E 5E 3Y .6Y | 5Y 5E 5E 6Y '1Y |

1Y 1E 1E 1Y .6Y | 2Y 2E 3E 6Y 5Y | 3Y 3E 5E 3Y 2Y | 1E .6E 1E 2E 3E 2E 3E 5E | 6E 5E 6E '1E 5E 6E 5E 3E | 2E 3E 2E 1E 2E 1E .6E 1E | .6 6 |

0Y .6Y 1Y 3Y | 0Y .6Y 1Y 3Y | 0Y 2Y .7Y 2Y | .6Y 3Y 1Y 3Y | 0Y .6Y 1Y 3Y | 0Y .6Y 1Y 3Y | 0Y 2Y .7Y 2Y | .6Y 3Y 1Y 3Y | 0Y .6Y 1Y 3Y |

0Y .6Y 1Y 3Y | 0Y 2Y .7Y 2Y | .6Y 3Y 1Y 3Y | 0Y 5Y 3Y 2Y | 1Y 2Y 1Y .6 | 2Y 2Y 3Y 1Y | .6. 3E 5E | .6. 3E 5E | .6. 3E 5E |

.6. 3E 5E | .6. 1E 2E | 3E 2E 3E 5E 6E '1E 6E 5E | 3E 2E 3E 5E 6E '1E 6E 5E | 3E 5E 3E 2E 1Y 3Y | .6. 1E 2E | 3E 2E 3E 5E 6E '1E 6E 5E | 3E 2E 3E 5E 6E '1E 6E 5E |

3E 5E 3E 2E 1Y 3Y | .6. 3E 6E | '1Y 6Y 6Y '3Y | '1Y 6Y 6Y 3Y | '1Y 6Y 6Y '3Y | '1Y 6Y 6Y 3Y | 1Y .6E 1E 2Y 1E 2E | 3Y 2E 3E 5Y 3E 5E |

5Y 3E 5E 6Y 5E 6E | '1Y 6E '1E '2Y '1E '2E | '3E '2E '1E '2E '3E '2E '1E '2E | '3E '2E '1E '2E '3E '2E '1E '2E | '3E '2E '1E '2E '3E '2E '1E '2E | '3E '2E '1E '2E '3E '2E '3E '5E |

'6^ '6^ | '6^ '6^ | '6^ '6 | '6 0 | 6 6 | .6^ .6 ||

上述文件存为1.txt,和midi.py , test.py放在同一个文件夹下,运行test.py

Tracks为文本中[]的个数,instrument为乐器号取值范围为0-127.

注:后附mid文本编辑规范。

附录

Midi文本需按以下格式书写。

<3|8> <120>#每分钟的节拍数

[1]

||...||

[2]

||...||

//////////////////////////////////////////////////////////////////////////////////////////////////////

||1. ''2. ..3. 4^ -^ - #5 b6 7Y. ''1Y^ -^ -||

#1'表示升高一个八度。[''1]表示比1高两个八度。

#2.在音符前表示降低一个八度。如[..6]表示比6低两个八度。

#3.在音符后表示付点音符。如[6.]

#4Y表示8分音符,即“一条横线”。如[6Y]

#5E表示16分音符,即“二条横线”。如[6E]

#6S表示32分音符,即“三条横线”。如[6S]

#7#表示升高半音

#8b表示降低半音

#9-表示延长一个四分音符。如[6^ -]

#10^表示两个相同的音相连。如6 -表示为6^ -

注:

1。对于表示升降的符号['],[.]后需紧接音符。

2。附点音符[.],[^]需紧接在音符之后。

[^]前后两个音必须相同,即[6^ 6][6^ -]

3[Y],[E],[S]需紧接在音符之后。

4。空格的作用非常重要,慎用。

音符后接空格表示此音符已结束。

5。其他功能,像控制器之类,还有待完善!对于升降音因为很少用就忽略了。编辑后的文学习使人进步

本需以1.txt命名。

本人刚学python不足之处请高手指教。本文代码在wm5 sp手机上编辑和测试。

python编写的midi制作软件

相关推荐