Как я могу воспроизводить музыку, представленную в виде аккордов в файле csv с помощью Python?

#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/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)
  

Код загружает набор данных Bach chorales и разархивирует его. Он состоит из 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 (C1 = C на октаве 1) до 81 (A5 = A на октаве 5), плюс 0 для тишины.

Мой вопрос заключается в следующем: как я могу воспроизвести эти хоралы на Python? Например, я хочу послушать их, как они звучат. Извлеченные файлы разделены на 3 каталога: train , valid , и test . Файлы в этих каталогах представляют .csv собой файлы с 4 столбцами в каждом ( note0 , note1 , note2 , и note3 ), по одному столбцу для каждой возможной нажатой клавиши пианино в каждом аккорде хорала. Как я могу превратить эти списки чисел во что-то, что я могу слушать? Я никогда не делал этого раньше, поэтому понятия не имею, как с этим справиться. Надеюсь, я ясно объяснил, что я хочу сделать: я хочу превратить эти хоралы из 3 файлов train , valid , и test в реальный звук на python, другими словами, превратить эти числа в настоящую музыку, сочиненную Бахом.

Комментарии:

1. Если вы можете преобразовать данные в MIDI-файлы, то есть доступные модули, которые могут их воспроизводить.

2. @martineau Хорошо, но как я могу преобразовать данные в MIDI-файлы?

3. Я уверен, что для этого есть и другие сторонние модули.

Ответ №1:

Пользователь github, с которого вы загружаете обработанные хоралы Баха, имеет собственный синтезатор, который он использует для генерации звуковых частот, чтобы услышать музыку.

 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])
  

Источник: https://colab.research.google.com/github/ageron/handson-ml2/blob/master/15_processing_sequences_using_rnns_and_cnns.ipynb и исходный код репозитория https://github.com/ageron/handson-ml2

Запустите первую ячейку настройки, затем перейдите к разделу 10, чтобы увидеть звуковую ячейку в действии.