Организовать музыку Григорианской Церкви


19

930 год, и у Григорианской Церкви есть проблема. У них тысячи страниц музыкального пения, но проблема в том, что все ноты были просто брошены в кучу, вместо того, чтобы иметь какую-либо реальную систему организации:

Изображение ноты
Изображение пользователя gamerprinter в Гильдии картографов .

Церкви нужно организовать все ноты, поэтому они наняли средневекового инженера-программиста, чтобы написать программу, чтобы организовать ее для них. Вы - инженер по программному обеспечению, который был нанят. Тем не менее, процесс компиляции в средневековье вовлекает программу, написанную на бумаге командой медленных библейских писцов. Чтобы уменьшить время, необходимое команде сценаристов для компиляции вашего кода, вы должны сделать программу как можно меньше.

Церковь хочет, чтобы музыка пения была организована исходя из музыкальной гаммы, в которой они написаны. Вся музыка пения Церкви написана в дорических масштабах . Учитывая ноты определенного музыкального произведения, ваша программа выведет шкалу Дориана, в которой она находится. Здесь я объясню, что такое шкала Дориана. Если вы уже знаете, вы можете пропустить этот раздел.

В любой мелодии 12 возможных нот. Вот они в порядке:

C C# D D# E F F# G G# A A# B

Полутона (представлено с использованием S) является приращение на один шаг вправо, обтекание (так полутон вверх от B будет обратно в C). Тональный сигнал (представлен с использованием T) два полутона. Например, полутон вверх от F # будет G. Тон вверх от F # будет G #.

Чтобы создать шкалу Дориана, мы начинаем с любой заметки в списке, а затем перемещаемся вверх по следующему шаблону, перечисляя встречающиеся заметки:

T, S, T, T, T, S

Пример. Я начинаю с А. Примечания моей дорианской шкалы становятся:

A
B  (up a tone)
C  (up a semitone)
D  (up a tone)
E  (up a tone)
F# (up a tone)
G  (up a semitone)

Шкала имеет ноты A, B, C, D, E, F # и G. Так как я начал с А, мы называем это Дориан масштаба в . Таким образом, существует 12 различных шкал Дориана, каждая из которых названа в честь записки, с которой они начали. Каждый из них использует один и тот же шаблон тонов и полутонов, только начиная с другой позиции. Если мое объяснение не является последовательным, вы также можете обратиться к Википедии .

Ввод программы может быть получен из того, что подходит для вашей программы (например, STDIN, аргумент командной строки, raw_input()). Это может быть предварительно не инициализировано в переменной. На входе будет список нот, разделенных запятыми, представляющих мелодию произведения. Там могут быть повторные заметки. На входе всегда будет достаточно разных заметок, чтобы можно было окончательно определить масштаб произведения. Пример ввода:

B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A

Выходные данные программы должны быть строкой Dorian scale in X, где X - начальная нота шкалы. Выходные данные примера ввода:

Dorian scale in B

Сравнивая это с дорианской шкалой в B ( B C# D E F# G# A), мы видим, что все ноты мелодии находятся в пределах этой шкалы. Примечание C # в этом случае не используется. Однако есть достаточно примечаний, чтобы однозначно идентифицировать Б. Дориана как правильный ключ. Никакая другая шкала Дориана не подходит, потому что независимо от того, какую другую шкалу мы пробуем, всегда есть хотя бы одна нота мелодии, которая не принадлежит этой шкале.

Это код гольф, поэтому выигрывает вход с кратчайшим количеством символов. Задайте в комментариях, если у вас есть вопросы.


Итак, что нам нужно сделать, это интерпретировать только первый тон / полутон?
Avall

@ Avall Извините, я не понимаю вашего вопроса. Ввод не всегда начинается с тоника, если это то, что вы просите.
Абсент

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

1
Обратной проблемой является шкала от ключа и мода
Питер Тейлор

1
@ Дэвид В соответствии с этим мета-вопросом , я присудил согласие на самый короткий ответ после 12-дневного периода ожидания с момента начала испытания. Так получилось, что ответ CJam был опубликован именно тогда, когда я собирался принять следующий самый короткий ответ .
Абсент

Ответы:



8

С 171 146

i,b;main(int c,char**v){for(;c=v[1][i];)b|=c/65<<c*2%7+v[1][++i]%2*7;for(i=12;i--;)b&(1016056>>i)||printf("Dorian scale in %c%c",65+i*3%7,(i<5)*35);}

Разбирать строки в C не так просто, поэтому я выбрал более математический подход.

Я пользуюсь Кругом Пятых. Если мы упорядочим ноты в следующем порядке, основываясь на подсчете 7 полутонов за раз (известный как «пятый»), мы обнаружим, что все ноты, разрешенные в любом данном масштабе, образуют последовательный блок из 7 нот и все запрещенные ноты образуют последовательный блок из 5 нот.

F C G D A E B F# C# G# D# A#

(это круг, он оборачивается Fв конце.)

Положение натуральной ноты в приведенной выше последовательности можно рассчитать как (ASCII code) * 2 % 7. Затем, если следующий символ нечетный (применяется, #но не запятая, пробел или нулевой байт), мы добавляем 7, чтобы сделать его резким. Мы храним растровое изображение заметок, которые были использованы.

Число 243(двоичное 11111000) соответствует примечаниям, запрещенным по шкале A # Dorian. Я умножил это (1<<12)+1=4097на магическое число 1016056. Это смещение прав для проверки (путем ANDing), содержит ли мелодия запрещенные ноты для каждой из 12 шкал по очереди. Если мелодия не содержит запрещенных нот, шкала печатается.

Для вывода нам нужно напечатать имя масштаба, закодированное в обратном порядке с циклом пятых выше, помните, что мы идем назад, потому что мы меняем права.) Последовательность ASCII ADGCFBEADGCFгенерируется с помощью 65+i*3%7. Для первых пяти из них острый также должен быть напечатан.

Код без правил

i,b;
main(int c,char**v){
  for(;c=v[1][i];)                          //for each character in first commanline argument v[1]
                                               //if it is a letter (assume uppercase, ASCII 65 or over)
   b|=c/65<<c*2%7+v[1][++i]%2*7;               //convert to position in the circle of fifths. 
                                               //Add 7 if the next character is odd (ASCII'#')
                                               //leftshift 1 by this number and OR this with the contents of b.

  for(i=12;i--;)b&(1016056>>i)||printf         //if melody includes no prohibited notes for the scale i, print
   ("Dorian scale in %c%c",65+i*3%7,(i<5)*35); //the scale letter, and a # (ASCII 35) if required, otherwise an ASCII 0.
}

Недопустимое поведение при вводе: если недостаточно данных для однозначного определения масштаба, будут выведены все возможные масштабы. Если указана невозможная комбинация заметок, она ничего не выдаст. Примечания должны быть разделены запятой (или другим непробельным символом с четным кодом ASCII <= 64). Пробелы нельзя использовать, поскольку все после первого пробела будет считаться другим аргументом. Коды ASCII> 64 будут интерпретироваться как примечания описанным способом.


Меня шокировало, что круг пятых обладает этим свойством! Может быть, я смогу использовать его для игры в гольф.
Рэй

1
@Ray Это на самом деле, почему у нас есть набор заметок, которые у нас есть. Октава имеет соотношение частот 2: 1. Пятый по определению Пифагора имеет соотношение 3: 2 и является самым важным музыкальным интервалом после октавы. Поскольку 1.5 ^ 12 близко к 2 ^ 7, но не равно 2 ^ 7, современная равная закаленная пятая сжимается до 1.4983, так что ровно 12 пятых помещаются в 7 октав. Старомодное решение состояло в том, чтобы использовать только 7 заметок из 12 доступных из круга. Вот почему у нас есть шкала, основанная на 7 неравномерно распределенных нотах. Это не какое-то случайное соглашение, за ним стоит солидная математика.
Уровень Река St

Существует ряд инструментов, которые упорядочивают ноты в пятых по соображениям удобства (скрипка настраивается таким образом, а бас-гитара настраивается в четвертых, что составляет соотношение 4: 3). Самым ярким примером (и единственным известным мне инструментом, который имеет заметки, выложенные в круг пятых для хорошего акустического дизайна), является steelpan: google.es/patents/US7696421 . При такой раскладке не имеет значения, что нота рядом с той, которую вы нажимаете, немного звонит.
Уровень Река St

4

Хаскелл - 152

w=words
n=w"C C# D D# E F F# G G# A A# B"
f s="Dorian scale in "++[n!!i|i<-[0..11],all(`elem`[(n++n)!!(i+j)|j<-[0,2,3,5,7,9,10]])s]!!0
main=interact$f.w

Ungolfed

type Note = String
type Scale = [Note]

notes :: [Note]
notes = words "C C# D D# E F F# G G# A A# B"

isScale :: Scale -> [Note] -> Bool
isScale scale notes = all (`elem` scale) notes

takeScale :: Int -> Scale
takeScale i = [(notes ++ notes) !! (i + j) | j <- [0, 2, 3, 5, 7, 9, 10]]

findScale :: [Note] -> Note
findScale xs = head [notes !! i | i <- [0..11], isScale (takeScale i) xs]

main = interact (("Dorian scale in "++) . findScale . words)

3

Python 2 - 177 символов

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

j=set(raw_input().split(','))
print"Dorian Scale in",[x for x in[["A A# B C C# D D# E F F# G G#".split()[(b+n)%12]for n in[0,2,3,5,7,9,10]]for b in range(12)]if j<set(x)][0][0]

Я не использую Python 3, но я считаю, что это редкий случай, когда для оператора print не нужно больше символов. Поскольку там printесть функция, я мог бы компенсировать необходимость использования скобок с помощью *оператора распаковки списка для замены последнего [0].


2
Вы бы также быть в состоянии заменить inputна raw_inputи сохранить 4 -х символов в Python 3.
comperendinous

«Я нахожу для Python радостью писать несколько вложенных циклов в одну строку»: но вы находите радость, читая их?
Калеб Пол

@ Wideshanks Конечно нет ... это все о коде только для записи!
feersum

3

Рубин - 132

12.times{|i|$*[0].split(?,)-(g=(0..6).map{|j|%w{C C# D D# E F F# G G# A A# B}[-i+=~(58>>j&1)]})==[]?(puts"Dorain scale in "+g[0]):g}

Ввод из аргументов командной строки.
напримерruby dorianscale.rb B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A

Попробуйте это на: ideone


3

Хаскель - 140

Используйте свойство Circle of Fifths, представленное @steveverrill. Если мы позволим circle0 = words "C G D A E B F# C# G# D# A# F"и circle = circle0 ++ circle0, то мы можем построить все шкалы, сделав последовательные 7 примечаний в circle.

scales = [take 7 . drop i $ circle | i <- [0..11]]

В каждой построенной таким образом scale !! 3шкале 4-й элемент является именем шкалы.

Код

w=words
n=w"C G D A E B F# C# G# D# A# F"
f s="Dorian scale in "++[x!!3|x<-[take 7.drop i$n++n|i<-[0..]],all(`elem`x)s]!!0
main=interact$f.w

Ungolfed

type Note = String
type Scale = [Note]

notes :: [Note]
notes = words "C G D A E B F# C# G# D# A# F"

scales :: [Scale]
scales = [take 7 . drop i $ notes ++ notes | i <- [0..11]]

findScale :: [Note] -> Note
findScale xs = head [scale !! 3 | scale <- scales, all (`elem` scale) xs]

main = interact (("Dorian scale in "++) . findScale . words)

2

Scala, 130 128 127

print("Dorian scale in "+(".#?".r findAllIn "FCGDAEBF#C#G#D#A#"*2 sliding(7)find{l=>args(0)split','forall(l contains _)}get 3))

Используя метод круга пятых. Ввод из аргументов командной строки т.е.

scala dorianscale.scala B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.