На самом деле я хотел написать код, чтобы преобразовать песню в ноты. для этого я нашел интервалы между соседними заметками, а затем мне нужен алгоритм для округления этих интервалов. Я сделал это, и это работает хорошо, я думаю. Сначала я нашел значение основного разрыва, например, в «102 103 402 409 390 398 100 200 408», основной разрыв - что-то около 400 (в среднем 402 409 390 398 408), затем я положил его длительность как 1 и сравнилдругой с этим. на 102 длительность составит 0,25 и тд.
Отредактировано: Frist Я использовал несколько библиотек python для обработки файла .mp3 и поиска момента изменения частоты и его соответствующей продолжительности в миллисекундах. Поскольку эти времена не являются точными, мне нужно округлить их, чтобы я мог назначить им одну из нотаций примечаний.
def roundOff(diffs):
global major_element, ref_offset, divide_flag, measured_time, measured_note
major_element = findMajor(diffs)
for element in diffs:
divide_flag = False
measured_time = 0
measured_note = 0
note_duration.append(noteFinder(element, ref_offset))
return note_duration
Вышеприведенная функция получает пропуски в качестве входных данных и возвращает соответствующую длительность ноты. Я нашел основной разрыв следующим образом:
def findMajor(diffs):
diffs_copy = diffs.copy()
diffs_copy.sort()
this = 0
for element in diffs_copy:
if isNear(element, this):
temp_this = (this*elements_in_gap[this] + element)/(elements_in_gap[this] + 1)
elements_in_gap[this] += 1
elements_in_gap[temp_this] = elements_in_gap.pop(this)
this = temp_this
else:
this = element
elements_in_gap[this] = 1
return max(elements_in_gap, key = element_in_gap.get)
Во-первых, он сортирует список пробелов и помещает 'this' в качестве репрезентативного значения разрыва, с которым мы хотим проверить других (начальное значение равно 0), вкаждый шаг, он проверяет, находится ли новый разрыв около 'this', затем изменяет 'this' и увеличивает количество разрывов в наборе 'this', но если он не рядом, замените 'this' на новый элемент и начальный номер нового 'this'(: |) в 1 и сделать то же самое. И, наконец, ключ возврата с наибольшим значением значения в качестве основного разрыва.
Функция isNear выглядит следующим образом:
def isNear(a, b):
if a < b+b*tolerance and a > b-b*tolerance:
return True
return False
В этом случае целесообразно установить допуск равным 0,1. noteFinder находит примечание каждого разрыва относительно основного разрыва как 1 (ref_offset).
def noteFinder(diff_time, offset):
global measured_time, measured_note, divide_flag, major_element
if isNear(diff_time, measured_time):
return measured_note
else:
if not divide_flag:
if diff_time > measured_time:
measured_time += offset*major_element
measured_note += offset
return noteFinder(diff_time, offset)
else:
offset /= 2
measured_time -= offset*major_element
measured_note -= offset
divide_flag = True
return noteFinder(diff_time, offset)
else:
offset /= 2
if diff_time > measured_time:
measured_time += offset*major_element
measured_note += offset
return noteFinder(diff_time, offset)
else:
measured_time -= offset*major_element
measured_note -= offset
return noteFinder(diff_time, offset)
Добавляет смещение к измеренной ноте и смещение * значение основного разрыва к измеренному времени на каждом шаге (сначаласмещение равно 1, как уже упоминалось), пока его значение разрыва не будет меньше измеренного времени, тогда он включит divid_flag, чтобы разделить смещение на 2 на каждом шаге, и попытается приблизиться к значению разрыва, а затем вернет записку meatured.
Это моя предложенная схема, если у вас есть лучшая, пожалуйста, дайте мне знать.