--*--
(!)有更新版本:Python音乐制作-紧急修复版v1.2_Unconquerable&Llxy的博客-CSDN博客
--*--
外来库:Pysynth
PySynth — A Music Synthesizer for Python
https://mdoege.github.io/PySynth/#d
文件资源:
音色有多种,取决于不同模块。这里不过多赘述。
上 代 码
文件(1)melody.py
- # coding:utf-8
-
- """
- ----------------------------------
- * author: Unconquerable *
- ----------------------------------
- a great tool to convert melody text to music.
- """
-
- class sound(object):
- high=4
-
- def __init__(self,high=4):
- self.high=high
- def __del__(self):
- del self.high
- def __str__(self):
- return ""
-
- def upLoud(self,up=1):
- self.high+=up
- def downLoud(self,down=1):
- self.high-=down
- def absoluteLoud(self,abv=0):
- self.high+=abv
- absLoud=absoluteLoud
- def resetLoud(self,value=4):
- self.high=value
- init=resetLoud
-
- @property
- def toString(self):
- return self.__str__()
- real=toString
-
- def plus(self):
- ...
-
- def plus_(self,num):
- ...
-
- def nplus(self):
- ...
-
-
- class C(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "c"+str(self.high)
-
- def plus(self):
- return AddC(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return B(self.high-1)
-
-
-
- class AddC(sound):
- high = 4
- def __init__(self,high):
- super().__init__(high)
- def __str__(self):
- return "c#"+str(self.high)
- def plus(self):
- return D(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return C(self.high)
-
- class D(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "d"+str(self.high)
- def plus(self):
- return AddD(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return AddC(self.high)
-
- class AddD(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "d#"+str(self.high)
- def plus(self):
- return E(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return D(self.high)
-
- class E(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "e"+str(self.high)
- def plus(self):
- return F(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return AddD(self.high)
-
- class F(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "f"+str(self.high)
- def plus(self):
- return AddF(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return E(self.high)
-
- class AddF(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "f#"+str(self.high)
- def plus(self):
- return G(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return F(self.high)
-
- class G(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "g"+str(self.high)
- def plus(self):
- return AddG(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return AddF(self.high)
-
- class AddG(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "g#"+str(self.high)
- def plus(self):
- return A(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return G(self.high)
-
- class A(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "a"+str(self.high)
- def plus(self):
- return AddA(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return AddG(self.high)
-
- class AddA(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "a#"+str(self.high)
- def plus(self):
- return B(self.high)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return A(self.high)
-
- class B(sound):
- high = 4
- def __init__(self,high=4):
- super().__init__(high=high)
- def __str__(self):
- return "b"+str(self.high)
- def plus(self):
- return C(self.high+1)
-
- def plus_(self, num):
- if num == 0: return self
- if num < 0:
- return self.nplus().plus_(num + 1)
- if num > 0:
- return self.plus().plus_(num - 1)
-
- def nplus(self):
- return AddA(self.high)
-
- class NULL(sound):
- def __str__(self):
- return "r"
- class time(object):
- real = 0
- def __init__(self,time=4):
- self.real= 4/time
-
- class note(object):
- sound_ = sound()
- time_ = time()
-
- def __init__(self,sd,t):
- self.soundSet(sd)
- self.timeSet(t)
-
- def soundSet(self,sd):
- if isinstance(sd,str):
- nd=sd[:-1].upper()
- dct={"C":C,"C#":AddC,"D":D,"D#":AddD,"E":E,"F":F,
- "F#":AddF,"G":G,"G#":AddG,"A":A,"A#":AddA,"B":B,"R":NULL}
- self.sound_=dct[nd](int(sd[-1]))
- if isinstance(sd,sound):
- self.sound_=sd
- if isinstance(sd,tuple):
- nd = sd[:-1].upper()
- dct = {"C": C, "C#": AddC, "D": D, "D#": AddD, "E": E, "F": F,
- "F#": AddF, "G": G, "G#": AddG, "A": A, "A#": AddA, "B": B, "R": NULL}
- self.sound_ = dct[nd](int(sd[-1]))
-
- def timeSet(self,t):
- if isinstance(t,(int,float)):
- self.time_=time(t)
- if isinstance(t,time):
- self.time_=t
-
- @property
- def out(self):
- return self.sound_.toString,self.time_.real
- class wav:
- melody=C(4)
- sound=[]
- staticTime=1
- def __init__(self,text=None,split=' '):
- if text:
- self.load(text=text,split=split)
- def __del__(self):
- pass
-
- @property
- def getMelody(self):
- return self.melody
-
- @property
- def getSound(self):
- return self.sound
-
- @property
- def getTime(self):
- return self.staticTime
-
- def setTime(self,time):
- self.staticTime=time
-
- def setMelody(self,melody):
- self.melody=melody
- def loadOneNote(self,n):
- if isinstance(n,note):
- self.sound.append(n.out)
- if isinstance(n,str):
- n=n.strip()
- if n[0]=="0":
- t=self.staticTime
- for i in n[1:]:
- if i == "-": # 延音符号
- t += self.staticTime
- if i == "_": # 半音符号
- t /= 2
- # (!)不要让延音符号和半音符号同时出现
- if i == ".": # 附点音符
- t += t / 2
-
- self.sound.append(("r",4/t))
- return
- #简谱
- t=self.staticTime
- dct={
- 1:0,
- 2:2,
- 3:4,
- 4:5,
- 5:7,
- 6:9,
- 7:11
- }
- l=self.melody.plus_(dct[int(n[0])])
- for i in n[1:]:
- if i=="#":#升音符号
- l.plus()
- if i=="&":#降音符号
- l.nplus()
- if i=="-":#延音符号
- t+=self.staticTime
- if i=="_":#半音符号
- t/=2
- # (!)不要让延音符号和半音符号同时出现
- if i==".":#附点音符
- t+=t/2
- if i=="+":#升音
- l.upLoud(1)
- if i=="!":#降音
- l.downLoud(1)
-
- mixed=note(l,t).out
- self.sound.append(mixed)
- def load(self,text,split=''):
- if split!='':
- for i in text.split(split):
- self.loadOneNote(i)
- else:
- tp=""
- for i in text:
- if i.isnumeric():
- if tp.strip() != "":
- self.loadOneNote(tp.strip())
- tp=""
- tp+=i
-
- def make_wav(self,module="pysynth",bpm=120,transpose=0,pause=.05,boost=1.1,
- repeat=0,fn="out.wav", silent=False):
- __import__(module.lower()).make_wav(song=self.sound,bpm=bpm,transpose=transpose,
- pause=pause,boost=boost,repeat=repeat,
- fn=fn, silent=silent)
-
-
文件:2(可有可无,可以规定调用的规范)melody.pyi
- # coding:utf-8
-
- """
- ----------------------------------
- * author: Unconquerable *
- ----------------------------------
- a great tool to convert melody text to music.
- """
-
-
- from typing import Union
-
- class sound(object):
- high:int
-
- def __init__(self,high:int=4): ...
- def __del__(self): ...
- def __str__(self) -> str: ...
-
- def upLoud(self,up:int) -> None: ...
- def downLoud(self,down:int) -> None: ...
- def absoluteLoud(self,abv:int) -> None: ...
- absLoud=absoluteLoud
- def resetLoud(self,value:int) -> None: ...
- init=resetLoud
- @property
- def toString(self) -> str : ...
- real=toString
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class C(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(C,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class AddC(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(AddC,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class D(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(D,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class AddD(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(AddD,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class E(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(E,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class F(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(F,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class AddF(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(AddF,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class G(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(G,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class AddG(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(AddG,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class A(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(A,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class AddA(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(AddA,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class B(sound):
- high:int
-
- def __init__(self,high:int=4):
- super(B,self).__init__(high=high)
- ...
- def __str__(self) -> str: ...
-
- def plus(self) -> sound : ...
- def plus_(self,num:int) -> sound : ...
- def nplus(self) -> sound: ...
-
- class NULL(sound):
- def __str__(self) -> str: ...
-
- class time(object):
- real : int
- def __init__(self,time:int=4): ...
-
- class note(object):
- sound_ : sound
- time_ : time
-
- def __init__(self,sd:Union[sound,str,tuple],t:Union[time,int,float]): ...
-
- def soundSet(self,sd:Union[sound,str,tuple]) -> None: ...
-
- def timeSet(self,t:Union[time,int,float]) -> None: ...
-
- @property
- def out(self) -> tuple[str,int]: ...
-
- class wav:
- melody:sound
- sound:list
- staticTime:Union[int,float]
-
- def __init__(self,text:Union[str,None]=None,split:str=' ') : ...
- def __del__(self) : ...
-
- @property
- def getMelody(self) -> str: ...
-
- @property
- def getSound(self) -> list: ...
-
- @property
- def getTime(self) -> Union[int,float]:...
-
- def setTime(self,time:Union[int,float]) -> None: ...
- def setMelody(self,melody:sound) -> None: ...
- def loadOneNote(self,n:str) -> None: ...
- def load(self,text:str,split:str=' ') -> None: ...
-
- def make_wav(self,module:str="pysynth",bpm:Union[int,float]=120,transpose:int=0,pause:float=.05,
- boost:float=1.1,repeat:int=0,fn:str="out.wav", silent:bool=False) -> None: ...
调用(1.py,同目录,父目录名称为MELODY。):
第三行import语句根据情况自行更改。
open里面的文件名自定。
- # coding=utf-8
-
- from MELODY.melody import *
-
-
- a=wav()
-
- text=open(r".\1.txt").read()
- text=text.split("-*-")
-
- a.setMelody(note(text[1].strip(),1).sound_)
- a.setTime(int(text[2].strip()))
-
- a.load(
- str(text[3]).strip()
- )
- res=text[0].strip().split("|")
-
- a.make_wav(module=res[0],bpm=eval(res[1]),repeat=eval(res[2]),fn=res[3])
1.txt:
格式为:
- 字符串,引用模块名|整数|整数|存储文件名
- -*-
- 调式,例如:1=C则填写c,1=降B则填写a#(即升a)
- -*-
- 节拍。例如,默认为每个音四分音符,即1 。
- -*-
- (乐谱部分)
注意:上面的部分基本不用更改。接下来是我写的一个模板。
- pysynth|120|0|file.wav
- -*-
- c
- -*-
- 1
- -*-
接下来要进行介绍。
第一行,以"|"分割。
"pysynth"表示使用默认音色。音色列表见下:
PySynth_A
这种加法单声道合成器非常简单,听起来有点像长笛或风琴,结合了钢琴般的音符音量衰减。PySynth A 只需要 Python 本身。它应该在所有 Python 支持的平台上运行,例如 Windows、Unix 和 Mac。PySynth_B
一个加法合成器模块,它试图用更多的谐波创建更像钢琴的声音。这个版本是复调的,因为它不会在下一个音符响起时切断前一个音符。
PySynth_C
PySynth C 是一种基于减法合成的简单弓弦音色。它使用锯齿波振荡器和低通滤波器,类似于 1970 年代的模拟合成器(或amsynth中的弦乐声音,或来自MOS Technology SID的声音)。与 PySynth A 一样,它只需要 Python 本身即可运行。
PySynth_D
PySynth D 使用与 PySynth C 类似的减法合成,但它基于方波。这种合成器主音类型的声音让人联想到木管乐器。方波也用于 1970 年代/1980 年代的计算机声音芯片,例如General Instrument AY-3-8910或Atari POKEY。只需要 Python 本身。
PySynth_E
该模块基于 PySynth B,基于相位调制创建简单的电子钢琴声音,这是进行 FM 合成的常用方法,例如在 1980 年代 Yamaha 合成器上。这种声音当然是受到Yamaha DX7上的 Rhodes 钢琴的启发。
PySynth_P
PySynth P 使用与 PySynth C 和 D 类似的减法合成,但基于具有指数体积包络的白噪声。它会产生未经调音的打击乐声音。这种类型的声音在 1980 年代通常用于打击乐和游戏音效。只需要 Python 本身。
PySynth_S
该模块使用Karplus-Strong 算法(想想吉他或大键琴)模拟单个弹拨。由于这种合成的性质,特别是较高频率的音符可能会与 PySynth S 稍微不协调,这与谐波精确的其他变体相反。这可以通过更高的采样率来解决,但这也会使其对 Python 来说有点慢。
PySynth_beeper
这个贡献的合成器属于nokiacomposer2wav.py并且应该重新创建老式诺基亚功能手机的铃声。
PySynth_samp
此合成器使用 48 kHz、24 位Salamander 钢琴样本。请在第 50 行设置 Salamander WAV 的路径(包括尾部斜杠)。
第二个值120表示了一分钟内演奏多少个四分音符。
第三个值是重复次数,默认为0,即不重复。
第四个值是文件存储路径。
第三行,一个值,表示调式。可选的有:
c c# d d# e f f# g g# a a# b
第五行,一个值,表示一个数字算作几个四分音符。如果没有特殊需要,填1就可以
乐谱部分。
简谱表示
升音用#
降音用&
半音用_
延音用-
附点用.
高八度用+
降八度用!
(全部用英文符)
接下来会逐渐(断断续续)发布一些相关的音乐材料(txt文件,用刚才的1.py解释一下就可以导出为wav文件了)
OK再~见~~~