Подтвердить что ты не робот

Определить ключ песни своими аккордами

Как я могу программно найти ключ песни, просто зная последовательность аккордов песни?
Я спросил некоторых людей, как они определят ключ от песни, и все они говорили, что делают это "по уху" или "проб и ошибок", и сообщая, разрешает ли аккорд песню или нет... Для среднего музыканта, который вероятно, прекрасно, но как программист, который действительно не является тем ответом, который я искал.

Итак, я начал искать библиотеки, связанные с музыкой, чтобы узнать, написал ли кто-нибудь еще алгоритм для этого. Но хотя я нашел очень большую библиотеку под названием "tonal" на GitHub: https://danigb.github.io/tonal/api/index.html Я не смог найти метод, который бы принял массив аккорды и вернуть ключ.

Мой язык выбора будет JavaScript (NodeJs), но я не обязательно ищу ответ на JavaScript. Псевдокод или объяснение, которое может быть переведено в код без особых проблем, было бы полностью прекрасным.

Как некоторые из вас упомянули правильно, ключ в песне может измениться. Я не уверен, что изменение ключа может быть обнаружено достаточно надежно. Итак, на данный момент, скажем так, я ищу алгоритм, который хорошо аппроксимирует ключ данной последовательности аккордов.

4b9b3361

Ответ 1

Аккорды в песне определенного ключа являются преимущественно членами ключевой шкалы. Я думаю, вы могли бы получить хорошее приближение статистически (если данных достаточно), сравнивая преобладающие случайности в аккордах, перечисленных в ключевых подписях ключей.

См. https://en.wikipedia.org/wiki/Circle_of_fifths

Конечно, песня в любой клавише может/иметь случайности не в шкале клавиш, поэтому она, скорее всего, будет статистической аппроксимацией. Но в нескольких барах, если вы добавляете случайные ситуации и отфильтровываете все, кроме тех, которые происходят чаще всего, вы можете соответствовать ключевой сигнатуре.

Добавление: как правильно указывает Jonas w, вы можете получить подпись, но вы вряд ли сможете определить, является ли это основным или второстепенным ключом.

Ответ 2

Возможно, вы также сохраните структуру с ключами для каждого "поддерживаемого" шкалы, а в качестве значения - массив с аккордами, соответствующими этому масштабу.

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

С несколькими совпадениями вы можете попытаться сделать обоснованное предположение. Например, добавьте другой "вес" в любой масштаб, соответствующий коренной ноте.

Ответ 3

Для массива таких тонов:

var tones = ["G","Fis","D"];

Сначала мы можем сгенерировать уникальный набор тонов:

tones = [...new Set(tones)];

Затем мы могли проверить наличие # и bs:

var sharps = ["C","G","D","A","E","H","Fis"][["Fis","Cis","Gis","Dis","Ais","Eis"].filter(tone=>tones.includes(tone)).length];

Затем сделайте то же самое с bs и получите результат с помощью:

var key = sharps === "C" ? bs:sharps;

Тем не менее, вы все еще не знаете, не слишком ли важны его основные или второстепенные, а многие компоненты не заботятся о верхних правилах (и изменили ключ между ними)...

Ответ 4

Вы можете использовать спиральный массив, 3D-модель для тональности, созданной Elaine Chew, которая имеет алгоритм обнаружения ключей.

Чуан, Чинг-Хуа и Элейн Чу. " Поиск полифонического аудио ключа с использованием алгоритма CEG спиральной матрицы." Multimedia and Expo, 2005. ICME 2005. Международная конференция IEEE. IEEE, 2005.

Моя недавняя модель натяжения, которая доступна в . jar file здесь, также выводит ключ (в дополнение к мерам натяжения) основанный на спиральной матрице. Он может либо взять файл musicXML или текстовый файл в качестве входных данных, который просто принимает список имен высоты для каждого "временного окна" в вашей части.

Herremans D., Chew E.. 2016. Ленты растяжения: квантование и визуализация тонального напряжения. Вторая Международная конференция по технологиям нотной музыки и представления (TENOR). 2:. 8-18

Ответ 5

Вот что я придумал. Все еще новые с современными JS так извиняются за беспорядочность и плохое использование карты().

Я осмотрел внутренности тональной библиотеки, у нее есть функция scalees.detect(), но это было бесполезно, поскольку она требовала присутствия каждой заметки. Вместо этого я использовал его как вдохновение и сгладил прогрессию в простой список заметок и проверил это во всех транспозициях как подмножество всех возможных масштабов.

const _ = require('lodash');
const chord = require('tonal-chord');
const note = require('tonal-note');
const pcset = require('tonal-pcset');
const dictionary = require('tonal-dictionary');
const SCALES = require('tonal-scale/scales.json');
const dict = dictionary.dictionary(SCALES, function (str) { return str.split(' '); });

//dict is a dictionary of scales defined as intervals
//notes is a string of tonal notes eg 'c d eb'
//onlyMajorMinor if true restricts to the most common scales as the tonal dict has many rare ones
function keyDetect(dict, notes, onlyMajorMinor) {
    //create an array of pairs of chromas (see tonal docs) and scale names
    var chromaArray = dict.keys(false).map(function(e) { return [pcset.chroma(dict.get(e)), e]; });
    //filter only Major/Minor if requested
    if (onlyMajorMinor) { chromaArray = chromaArray.filter(function (e) { return e[1] === 'major' || e[1] === 'harmonic minor'; }); }
 //sets is an array of pitch classes transposed into every possibility with equivalent intervals
 var sets = pcset.modes(notes, false);

 //this block, for each scale, checks if any of 'sets' is a subset of any scale
 return chromaArray.reduce(function(acc, keyChroma) {
    sets.map(function(set, i) {
        if (pcset.isSubset(keyChroma[0], set)) {
            //the midi bit is a bit of a hack, i couldnt find how to turn an int from 0-11 into the repective note name. so i used the midi number where 60 is middle c
            //since the index corresponds to the transposition from 0-11 where c=0, it gives the tonic note of the key
            acc.push(note.pc(note.fromMidi(60+i)) + ' ' + keyChroma[1]);
            }
        });
        return acc;
    }, []);

    }

const p1 = [ chord.get('m','Bb'), chord.get('m', 'C'), chord.get('M', 'Eb') ];
const p2 = [ chord.get('M','F#'), chord.get('dim', 'B#'), chord.get('M', 'G#') ];
const p3 = [ chord.get('M','C'), chord.get('M','F') ];
const progressions = [ p1, p2, p3 ];

//turn the progression into a flat string of notes seperated by spaces
const notes = progressions.map(function(e) { return _.chain(e).flatten().uniq().value(); });
const possibleKeys = notes.map(function(e) { return keyDetect(dict, e, true); });

console.log(possibleKeys);
//[ [ 'Ab major' ], [ 'Db major' ], [ 'C major', 'F major' ] ]

Некоторые недостатки:
- не дает требуемой энгармонической ноты. В p2 более правильным ответом является С# major, но это может быть исправлено путем проверки как-то с первоначальной прогрессией.
- не будет иметь дело с "украшениями" на аккорды, которые находятся вне ключа, что может происходить в поп-песнях, например. CMaj7 FMaj7 GMaj7 вместо C F G. Не знаю, насколько это распространено, не слишком много, я думаю.