是否可以使用 pyaudio 演奏和弦?
问问题
2088 次
2 回答
4
当然!
只需生成结果并将其传递给播放器即可。
以下是链接中的文章更改或失效的示例代码:
import math
import numpy
import pyaudio
import itertools
from scipy import interpolate
from operator import itemgetter
# https://davywybiral.blogspot.com/2010/09/procedural-music-with-pyaudio-and-numpy.html
class Note:
NOTES = ['c','c#','d','d#','e','f','f#','g','g#','a','a#','b']
def __init__(self, note, octave=4):
self.octave = octave
if isinstance(note, int):
self.index = note
self.note = Note.NOTES[note]
elif isinstance(note, str):
self.note = note.strip().lower()
self.index = Note.NOTES.index(self.note)
def transpose(self, halfsteps):
octave_delta, note = divmod(self.index + halfsteps, 12)S
return Note(note, self.octave + octave_delta)
def frequency(self):
base_frequency = 16.35159783128741 * 2.0 ** (float(self.index) / 12.0)
return base_frequency * (2.0 ** self.octave)
def __float__(self):
return self.frequency()
class Scale:
def __init__(self, root, intervals):
self.root = Note(root.index, 0)
self.intervals = intervals
def get(self, index):
intervals = self.intervals
if index < 0:
index = abs(index)
intervals = reversed(self.intervals)
intervals = itertools.cycle(self.intervals)
note = self.root
for i in range(index):
note = note.transpose(next(intervals))
return note
def index(self, note):
intervals = itertools.cycle(self.intervals)
index = 0
x = self.root
while x.octave != note.octave or x.note != note.note:
x = x.transpose(next(intervals))
index += 1
return index
def transpose(self, note, interval):
return self.get(self.index(note) + interval)
def sine(frequency, length, rate):
length = int(length * rate)
factor = float(frequency) * (math.pi * 2) / rate
return numpy.sin(numpy.arange(length) * factor)
def shape(data, points, kind='slinear'):
items = points.items()
sorted(items,key=itemgetter(0))
keys = list(map(itemgetter(0), items))
vals = list(map(itemgetter(1), items))
interp = interpolate.interp1d(keys, vals, kind=kind)
factor = 1.0 / len(data)
shape = interp(numpy.arange(len(data)) * factor)
return data * shape
def harmonics1(freq, length):
a = sine(freq * 1.00, length, 44100)
b = sine(freq * 2.00, length, 44100) * 0.5
c = sine(freq * 4.00, length, 44100) * 0.125
return (a + b + c) * 0.2
def harmonics2(freq, length):
a = sine(freq * 1.00, length, 44100)
b = sine(freq * 2.00, length, 44100) * 0.5
return (a + b) * 0.2
def pluck1(note):
chunk = harmonics1(note.frequency(), 2)
return shape(chunk, {0.0: 0.0, 0.005: 1.0, 0.25: 0.5, 0.9: 0.1, 1.0:0.0})
def pluck2(note):
chunk = harmonics2(note.frequency(), 2)
return shape(chunk, {0.0: 0.0, 0.5:0.75, 0.8:0.4, 1.0:0.1})
def chord(n, scale):
root = scale.get(n)
third = scale.transpose(root, 2)
fifth = scale.transpose(root, 4)
return pluck1(root) + pluck1(third) + pluck1(fifth)
root = Note('A', 3)
scale = Scale(root, [2, 1, 2, 2, 1, 3, 1])
chunks = []
chunks.append(chord(21, scale))
chunks.append(chord(19, scale))
chunks.append(chord(18, scale))
chunks.append(chord(20, scale))
chunks.append(chord(21, scale))
chunks.append(chord(22, scale))
chunks.append(chord(20, scale))
chunks.append(chord(21, scale))
chunks.append(chord(21, scale) + pluck2(scale.get(38)))
chunks.append(chord(19, scale) + pluck2(scale.get(37)))
chunks.append(chord(18, scale) + pluck2(scale.get(33)))
chunks.append(chord(20, scale) + pluck2(scale.get(32)))
chunks.append(chord(21, scale) + pluck2(scale.get(31)))
chunks.append(chord(22, scale) + pluck2(scale.get(32)))
chunks.append(chord(20, scale) + pluck2(scale.get(29)))
chunks.append(chord(21, scale) + pluck2(scale.get(28)))
chunk = numpy.concatenate(chunks) * 0.25
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32, channels=1, rate=44100, output=1)
stream.write(chunk.astype(numpy.float32).tostring())
stream.close()
p.terminate()
这是一个更好的来源
于 2014-04-11T01:19:25.700 回答
0
可以使用 pyaudio 一次播放多个音符。在之前对另一个问题的回答中,我在音符中添加了谐波,并添加了一些基本效果。以此为基础(并添加一些缓冲),如果您想使用音符而不是谐波来构建和弦,您可以定义您认为的和弦关系。在这里,我在和弦的第一次转位(或堆叠五度)中使用了基本的三度叠加,但如果您也需要,您可以定义一个更强大的和弦系统。无论如何,这是一个代码示例,说明如何执行此操作:
import math # import needed modules
import pyaudio
scale_notes = {
# pitch standard A440 ie a4 = 440Hz
'c': 16.35,
'C': 17.32,
'd': 18.35,
'D': 19.45,
'e': 20.6,
'f': 21.83,
'F': 23.12,
'g': 24.5,
'G': 25.96,
'a': 27.5,
'A': 29.14,
'b': 30.87
}
note_names = 'cCdDefFgGaAb'
def playnote(note, chord_style):
if chord_style == "min":
chord_tones = [0,3,7]
elif chord_style == "maj":
chord_tones = [0,4,7]
elif chord_style == "five":
chord_tones = [0,7]
else:
chord_tones = [0]
num_notes = len(chord_tones)
p = pyaudio.PyAudio() # initialize pyaudio
# sampling rate
sample_rate = 22050
LENGTH = 1 # seconds to play sound
frames = int(sample_rate * LENGTH)
wavedata = ''
# generating waves
stream = p.open(
format=p.get_format_from_width(1),
channels=1,
rate=sample_rate,
output=True)
CHUNK = 256
octave = int(note[1])
frequencies = []
for tone in chord_tones:
chord_note = note_names.index(note[0]) + tone
if chord_note<12:
chord_note = note_names[chord_note]
frequencies.append(scale_notes[chord_note] * (2**(octave + 1)))
print(frequencies)
else:
chord_note = note_names[chord_note-12]
frequencies.append( scale_notes[chord_note] * (2**(octave + 2)))
print(frequencies)
y=0
for x in range(frames//CHUNK):
n=0
wavedata=b''
while n<CHUNK:
wave=0
for freqs in frequencies:
wave += math.sin((y) / ((sample_rate / freqs) / math.pi)) * 127 + 128
wave = wave/num_notes
wavedata += bytes([int(wave)])
y+=1
n+=1
stream.write(wavedata)
stream.stop_stream()
stream.close()
p.terminate()
song = []
while True:
song_composing = True
note = ''
while note != 'p':
note = str(input(
'Enter note (a-G) (capital for sharp) and an octave (0-8) or any other key to play: '))
if note[0] in scale_notes:
chord_style = str(
input('Enter chord quality (maj, min, five): '))
song.append((note, chord_style))
playnote(note, chord_style)
for chord in song:
playnote(chord[0], chord[1])
break
所以在提示符下,如果你输入,d4 min, g4 maj, c4 maj
你会得到 C 中的 ii-VI 节奏。
于 2019-08-22T05:16:57.320 回答