如何使用Python在csv文件中播放和弦表示的音乐?

如何使用Python在csv文件中播放和弦表示的音乐?,python,Python,考虑以下代码: import numpy as np import pandas as pd from pathlib import Path from tensorflow import keras def load_chorales(filepaths): return [pd.read_csv(filepath).values.tolist() for filepath in filepaths] DOWNLOAD_ROOT = "https://github.com

考虑以下代码:

import numpy as np
import pandas as pd
from pathlib import Path
from tensorflow import keras

def load_chorales(filepaths):
    return [pd.read_csv(filepath).values.tolist() for filepath in filepaths]

DOWNLOAD_ROOT = "https://github.com/ageron/handson-ml2/raw/master/datasets/jsb_chorales/"
FILENAME = "jsb_chorales.tgz"
filepath = keras.utils.get_file(FILENAME,
                                DOWNLOAD_ROOT + FILENAME,
                                cache_subdir="datasets/jsb_chorales",
                                extract=True)


jsb_chorales_dir = Path(filepath).parent
train_files = sorted(jsb_chorales_dir.glob("train/chorale_*.csv"))
valid_files = sorted(jsb_chorales_dir.glob("valid/chorale_*.csv"))
test_files = sorted(jsb_chorales_dir.glob("test/chorale_*.csv"))

train_chorales = load_chorales(train_files)
valid_chorales = load_chorales(valid_files)
test_chorales = load_chorales(test_files)
代码下载巴赫合唱团的数据集并将其解压。它由约翰·塞巴斯蒂安·巴赫创作的382首合唱曲组成。每个合唱的时间步长为100到640,每个时间步长包含4个整数,其中每个整数对应钢琴上的音符索引(值0除外,该值表示不播放音符)。这是一个合唱(来自训练集)的示例:

print(train_chorales[0])
[[74, 70, 65, 58],
 [74, 70, 65, 58],
 [74, 70, 65, 58],
 [74, 70, 65, 58],
 [75, 70, 58, 55],
...
 [70, 65, 62, 46],
 [70, 65, 62, 46],
 [70, 65, 62, 46]]
它由192个时间步(或和弦,或192个4个值的列表组成。换句话说,上面的print语句将打印192行4个整数的列表)

在数据集中,音符的范围从36(1倍频程上的C1=C)到81(5倍频程上的A5=A),加上0表示静音


我的问题是:如何用Python播放这些合唱?我想听听他们的声音。提取的文件分为3个目录:
train
valid
test
。这些目录中的文件是
.csv
文件,每个文件有4列(
note0
note1
note2
,和
note3
),合唱中每个和弦中每个可能按下的钢琴键对应一列。我怎样才能把这些数字列表变成我能听到的东西呢?我以前从未这样做过,所以我不知道如何解决这个问题。我希望我清楚地说明了我想做什么:我想把这些合唱从3个文件
train
valid
,和
test
转换成python中的真实声音,换言之,将这些数字转换成巴赫创作的实际音乐。

github用户Agron您可以从下载处理过的巴赫合唱曲,他有自己的合成器,用于生成音频来听音乐

from IPython.display import Audio

def notes_to_frequencies(notes):
    # Frequency doubles when you go up one octave; there are 12 semi-tones
    # per octave; Note A on octave 4 is 440 Hz, and it is note number 69.
    return 2 ** ((np.array(notes) - 69) / 12) * 440

def frequencies_to_samples(frequencies, tempo, sample_rate):
    note_duration = 60 / tempo # the tempo is measured in beats per minutes
    # To reduce click sound at every beat, we round the frequencies to try to
    # get the samples close to zero at the end of each note.
    frequencies = np.round(note_duration * frequencies) / note_duration
    n_samples = int(note_duration * sample_rate)
    time = np.linspace(0, note_duration, n_samples)
    sine_waves = np.sin(2 * np.pi * frequencies.reshape(-1, 1) * time)
    # Removing all notes with frequencies ≤ 9 Hz (includes note 0 = silence)
    sine_waves *= (frequencies > 9.).reshape(-1, 1)
    return sine_waves.reshape(-1)

def chords_to_samples(chords, tempo, sample_rate):
    freqs = notes_to_frequencies(chords)
    freqs = np.r_[freqs, freqs[-1:]] # make last note a bit longer
    merged = np.mean([frequencies_to_samples(melody, tempo, sample_rate)
                     for melody in freqs.T], axis=0)
    n_fade_out_samples = sample_rate * 60 // tempo # fade out last note
    fade_out = np.linspace(1., 0., n_fade_out_samples)**2
    merged[-n_fade_out_samples:] *= fade_out
    return merged

def play_chords(chords, tempo=160, amplitude=0.1, sample_rate=44100, filepath=None):
    samples = amplitude * chords_to_samples(chords, tempo, sample_rate)
    if filepath:
        from scipy.io import wavfile
        samples = (2**15 * samples).astype(np.int16)
        wavfile.write(filepath, sample_rate, samples)
        return display(Audio(filepath))
    else:
        return display(Audio(samples, rate=sample_rate))

play_chords(train_chorales[0])
来源:和回购来源


运行第一个设置单元,然后转到第10节,查看音频单元的运行情况。

如果您可以将数据转换为MIDI文件,那么就有可以播放这些文件的模块。@martineau好的,但是如何将数据转换为MIDI文件呢?我很确定还有其他第三方模块可以用于此。