Tổ chức âm nhạc của nhà thờ Gregorian


19

Năm nay là 930, và Giáo hội Gregorian đang gặp vấn đề. Họ có hàng ngàn trang nhạc thánh ca, nhưng vấn đề là tất cả các bản nhạc chỉ đơn giản được ném lên một đống thay vì có bất kỳ hệ thống tổ chức thực sự nào:

Hình ảnh của bản nhạc
Hình ảnh của người chơi gamerprinter tại Cartographers 'Guild .

Giáo hội cần tổ chức tất cả các bản nhạc, vì vậy họ đã thuê một kỹ sư phần mềm thời trung cổ để viết một chương trình để tổ chức nó cho họ. Bạn là kỹ sư phần mềm đã được thuê. Tuy nhiên, quá trình biên soạn trong thời trung cổ liên quan đến chương trình được viết lên giấy bởi một nhóm các kinh sư chậm trong Kinh thánh. Để giảm thời gian cần thiết cho nhóm các nhà ghi chép để biên dịch mã của bạn, bạn phải làm cho chương trình càng nhỏ càng tốt.

Giáo hội muốn âm nhạc thánh ca được tổ chức dựa trên quy mô âm nhạc mà họ được viết. Tất cả nhạc thánh ca của Giáo hội được viết theo thang âm Dorian . Đưa ra các ghi chú của một bản nhạc nhất định, chương trình của bạn sẽ xuất ra thang âm Dorian. Nó ở đây, tôi sẽ giải thích chính xác thang âm Dorian là gì. Nếu bạn đã biết, bạn có thể bỏ qua phần này.

Có 12 nốt có thể trong bất kỳ giai điệu nào. Ở đây họ theo thứ tự:

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

Một nửa cung (được biểu diễn bằng cách sử dụng a S) đang tăng một bước sang phải, bao quanh (vì vậy một nửa cung từ B sẽ trở lại C). Một âm (được biểu diễn bằng a T) là hai nửa cung. Chẳng hạn, một nửa cung lên từ F # sẽ là G. Một âm lên từ F # sẽ là G #.

Để tạo thang đo Dorian, chúng tôi bắt đầu từ bất kỳ ghi chú nào trong danh sách, sau đó di chuyển lên theo mẫu sau, liệt kê các ghi chú mà chúng tôi gặp phải:

T, S, T, T, T, S

Một ví dụ. Tôi bắt đầu từ A. Các ghi chú của thang Dorian của tôi trở thành:

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)

Quy mô có ghi chú A, B, C, D, E, F #, và G. Bởi vì tôi bắt đầu từ A, chúng tôi sẽ gọi đây là quy mô Dorian A . Do đó, có 12 thang Dorian khác nhau, mỗi thang được đặt tên theo ghi chú mà chúng bắt đầu. Mỗi người trong số họ sử dụng cùng một mẫu âm và nửa cung, chỉ bắt đầu từ một vị trí khác nhau. Nếu lời giải thích của tôi không mạch lạc, bạn cũng có thể tham khảo Wikipedia .

Đầu vào của chương trình có thể được cung cấp từ bất cứ điều gì phù hợp với chương trình của bạn (ví dụ STDIN, đối số dòng lệnh, raw_input()). Nó có thể không được khởi tạo trước trong một biến. Đầu vào sẽ là một danh sách các ghi chú được phân tách bằng dấu phẩy, thể hiện giai điệu của bản nhạc. Có thể có ghi chú lặp đi lặp lại. Sẽ luôn có đủ các ghi chú khác nhau trong đầu vào để có thể suy luận quyết định tỷ lệ của mảnh. Một ví dụ đầu vào:

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

Đầu ra của chương trình phải là chuỗi Dorian scale in X, trong đó X là ghi chú bắt đầu của thang đo. Đầu ra của đầu vào ví dụ:

Dorian scale in B

So sánh điều này với thang âm Dorian trong B ( B C# D E F# G# A) chúng ta thấy rằng tất cả các nốt của giai điệu đều nằm trong thang âm này. Lưu ý C # không được sử dụng trong trường hợp này. Tuy nhiên, có đủ ghi chú để xác định rõ ràng B Dorian là khóa chính xác. Không có thang âm Dorian nào phù hợp, bởi vì bất kỳ thang âm nào khác mà chúng tôi thử, luôn có ít nhất một nốt nhạc của giai điệu không thuộc về thang âm.

Đây là mã golf, vì vậy, mục có số lượng nhân vật ngắn nhất sẽ thắng. Hỏi trong các ý kiến ​​nếu bạn có câu hỏi.


Vì vậy, những gì chúng ta nên làm là chỉ giải thích giai điệu / semitone đầu tiên?
trước

@Avall Tôi xin lỗi, tôi không hiểu câu hỏi của bạn. Đầu vào sẽ không luôn bắt đầu bằng thuốc bổ, nếu đó là những gì bạn đang hỏi.
absinthe

Vui lòng cung cấp cho chúng tôi nhiều ví dụ. Đặc biệt là những người không bắt đầu với thuốc bổ.
trước

1
Vấn đề nghịch đảo là Quy mô từ khóa và chế độ
Peter Taylor

1
@David Theo câu hỏi meta này , tôi đã trao phần chấp nhận cho câu trả lời ngắn nhất sau khoảng thời gian chờ đợi là 12 ngày kể từ khi tôi bắt đầu thử thách. Nó chỉ xảy ra câu trả lời của CJam đã được đăng ngay khi tôi định chấp nhận câu trả lời ngắn nhất tiếp theo.
absinthe

Câu trả lời:


2

CJam - 61

C,q',/f{"FCGDAEB"_5<'#f++:s@m<7<:A-!{"Dorian scale in "A3=}*}

Dùng thử tại http://cjam.aditsu.net/


Ồ, đây phải là chiến thắng nhanh nhất của tôi .. chưa đầy 1 phút :)
aditsu

8

C, 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);}

Phân tích chuỗi trong C không phải là dễ dàng, vì vậy tôi đã tìm kiếm một cách tiếp cận toán học hơn.

Tôi tận dụng Vòng tròn thứ năm. Nếu chúng tôi sắp xếp các ghi chú theo thứ tự sau dựa trên việc đếm 7 nửa cung một lần (được gọi là "thứ năm"), chúng tôi thấy rằng tất cả các ghi chú được phép trong bất kỳ thang đo nào đều tạo thành một khối 7 nốt liên tiếp và tất cả các ghi chú bị cấm tạo thành một khối liên tiếp gồm 5 nốt.

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

(đó là một vòng tròn, nó kết thúc xung quanh đến Fcuối.)

Vị trí của một ghi chú tự nhiên trong chuỗi trên có thể được tính như (ASCII code) * 2 % 7. Sau đó, nếu ký tự tiếp theo là số lẻ (áp dụng cho #nhưng không phải dấu phẩy, dấu cách hoặc byte bằng 0), chúng ta thêm 7 để làm cho nó sắc nét. Chúng tôi lưu trữ một bitmap của các ghi chú đã được sử dụng.

Số 243(nhị phân 11111000) tương ứng với các ghi chú bị cấm trong thang đo của A # Dorian. Tôi đã nhân số này bằng cách (1<<12)+1=4097đưa ra con số kỳ diệu 1016056. Đây là bản quyền để kiểm tra (bằng ANDing) nếu giai điệu chứa các nốt bị cấm cho mỗi trong số 12 thang âm. Nếu giai điệu không chứa các ghi chú bị cấm, thang âm được in.

Đối với đầu ra, chúng ta cần in tên tỷ lệ được mã hóa theo thứ tự ngược lại theo chu kỳ thứ năm ở trên, hãy nhớ rằng chúng ta sẽ quay ngược lại vì chúng ta đang chuyển quyền.) Trình tự ASCII ADGCFBEADGCFđược tạo bởi 65+i*3%7. Đối với năm đầu tiên, một sắc nét cũng phải được in.

Mã bị đánh cắp

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.
}

Hành vi nhập không hợp lệ: Nếu ghi chú không đủ được cung cấp để xác định rõ ràng tỷ lệ, nó sẽ xuất ra tất cả các tỷ lệ có thể. Nếu một sự kết hợp không thể của các ghi chú được cung cấp, nó sẽ không tạo ra gì. Các ghi chú phải được phân cách bằng dấu phẩy (hoặc ký tự không phải khoảng trắng khác có mã ASCII chẵn <= 64.) Không thể sử dụng dấu cách làm mọi thứ sau khoảng trắng đầu tiên sẽ được coi là một đối số khác nhau. Mã ASCII> 64 sẽ được hiểu là các ghi chú theo cách được mô tả.


Nó làm tôi sốc khi vòng tròn thứ năm có tài sản này! Có lẽ tôi có thể sử dụng nó để chơi gôn hơn một chút.
Ray

1
@Ray Đây thực sự là lý do tại sao chúng tôi có bộ ghi chú mà chúng tôi có. Quãng tám có tỷ lệ tần số 2: 1. Phần thứ năm theo định nghĩa của Pythagoras có tỷ lệ 3: 2 và là khoảng thời gian âm nhạc quan trọng nhất sau quãng tám. Vì 1,5 ^ 12 gần bằng nhưng không bằng 2 ^ 7, nên thứ năm nóng tính hiện đại được nén xuống còn 1.4983 để chính xác 12 phần năm phù hợp với 7 quãng tám. Giải pháp lỗi thời là chỉ sử dụng 7 nốt trong số 12 nốt có sẵn từ vòng tròn. Đó là lý do tại sao chúng tôi có một thang điểm dựa trên 7 ghi chú cách đều nhau. Đó không phải là một số quy ước ngẫu nhiên, có một số toán học vững chắc đằng sau nó.
Cấp sông St

Có một số nhạc cụ sắp xếp các nốt trong phần năm vì lý do thuận tiện (violin được điều chỉnh theo cách này và guitar bass được điều chỉnh ở phần tư, tỷ lệ 4: 3). Ví dụ nổi bật nhất (và nhạc cụ duy nhất tôi biết có ghi chú được đặt trong một vòng tròn thứ năm cho thiết kế âm thanh tốt) là steelpan: google.es/patents/US7696421 . Với cách bố trí này, không có vấn đề gì nếu ghi chú bên cạnh cái bạn đang nhấn một chút.
Cấp sông St

4

Haskell - 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

Bị đánh cắp

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 ký tự

Nó không phải là ngắn, nhưng tôi thấy đó là niềm vui của Python khi viết nhiều vòng lặp lồng nhau trong một dòng, ngay cả khi không chơi gôn. Thật không may, tôi đã phải đặt câu lệnh đầu vào trên một dòng riêng biệt để nó không thực thi nhiều lần.

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]

Tôi không sử dụng Python 3, nhưng tôi tin rằng đây là một trường hợp hiếm hoi khi câu lệnh in không cần thêm ký tự. Vì printlà một hàm ở đó, tôi sẽ có thể bù đắp sự cần thiết của dấu ngoặc đơn với việc sử dụng *toán tử giải nén danh sách để thay thế toán tử cuối cùng [0].


2
Bạn cũng muốn có thể thay thế inputcho raw_inputvà lưu 4 nhân vật trong Python 3.
comperendinous

"Tôi thấy đó là niềm vui của Python khi viết nhiều vòng lặp lồng nhau trong một dòng": nhưng bạn có tìm thấy niềm vui khi đọc chúng không?
Caleb Paul

@W slideshowanks Tất nhiên không phải ... đó là tất cả về mã chỉ viết!
frageum

3

Hồng ngọc - 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}

Đầu vào từ dòng lệnh args.
ví dụruby dorianscale.rb B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A

Hãy thử tại: ideone


3

Haskell - 140

Sử dụng thuộc tính Circle of Fifths được giới thiệu bởi @steveverrill. Nếu chúng ta cho circle0 = words "C G D A E B F# C# G# D# A# F"circle = circle0 ++ circle0, thì chúng ta có thể xây dựng tất cả các tỷ lệ bằng cách ghi 7 liên tiếp vào circle.

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

Trong mỗi thang đo được xây dựng theo cách này, scale !! 3phần tử thứ 4 là tên thang đo.

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

Bị đánh cắp

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

Sử dụng vòng tròn của phương pháp thứ năm. Đầu vào từ dòng lệnh args tức là

scala dorianscale.scala B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.