2025. 3. 17. 23:42ㆍDevelopers 공간 [Shorts]/Vision & Audio
<분류>
A. 수단
- OS/Platform/Tool : Linux, Kubernetes(k8s), Docker, AWS
- Package Manager : node.js, yarn, brew,
- Compiler/Transpillar : React, Nvcc, gcc/g++, Babel, Flutter
- Module Bundler : React, Webpack, Parcel
B. 언어
- C/C++, python, Javacsript, Typescript, Go-Lang, CUDA, Dart, HTML/CSS
C. 라이브러리 및 프레임워크 및 SDK
- OpenCV, OpenCL, FastAPI, PyTorch, Tensorflow, Nsight
1. What? (현상)
이번 글에서는 python에서 조성(조, Key)라고 불리는 장조/단조를 알아내는 좋은 소스가 있어 소개하려고 합니다.
먼저 조성이 무엇인지 살펴보겠습니다.
장조와 단조의 가장 큰 차이는 아래와 같이 구분됩니다.
- 장조 : "온온반온온온반"으로 구성된 스케일로 구성된 조성. 밝고 안정적인 분위기를 가집니다.
- 단조 : "온반온온반온온"으로 구성된 스케일로 구성된 조성. 어둡고 서정적인 분위기를 가집니다.
** 자연단음계를 기준으로 설명합니다.
아래와 같이 대표적인 장조는 C장조이며, 대표적인 단조는 A단조입니다. 이때, A 단조의 구성을 C단조에 대해 대입해보고 비교해보면 확실히 차이를 알 수 있습니다.
5도권을 기준으로 아래와 같은 규칙으로 장조와 단조의 스케일을 구성하며, 이 관계에서 아래 그림과 같이 나란한조, 같은 으뜸음조, 이명동음조 등이 발생합니다.
** 주의. 아래 그림에서 같은 으뜸음조는 이명동음조로 인해 왼쪽과 오른쪽이 일치하지 않을 수도 있습니다.
위에서 특히 나란한조는 같은 음계를 가지는 장조와 단조가 어떻게 다른느낌을 제공할 수 있는지 궁금할 수 있습니다.
이에 대해 간단히만 언급하자면, 스케일은 같더라도 악보를 만들 때 토닉음(중심음, 으뜸음)이 다르며, 악보를 구성하는 코드 즉 화성이 각각의 위치에서의 역할이 바뀌기 때문에 악보에서 느낌을 다르게 나타납니다.
그럼 노래를 듣고 이 조성을 알아내려면 보통 어떻게 할까요?
사람마다 다른 방법을 사용하겠지만, 필자는 아래와 같은 순서로 조성을 알아냅니다.
- 1. 곡의 전반적인 분위기나 정서를 바탕으로 메이저 키인지 마이너 키인지를 예측합니다.
- 2. 마지막 끝나는 음, 혹은 시작하는 음은 으뜸음일 가능성이 높습니다.
- 3. 주요 악절의 음을 청음하여 사용된 음계를 파악하고, 그 음계에 따라 어떤 조표(# 또는 ♭)가 해당 조성에 사용되는지를 유추합니다.
- 4. 조표를 바탕으로 가능한 조성을 추정하고, 이를 통해 해당 곡의 스케일과 조성을 더블체크합니다.
위 설명을 보시면 아시겠지만, 익숙하지 않다면 과정이 오래걸리고 정확하지도 않을 수도 있습니다.
이번 글에서는 이런 조성을 알아내는 코드를 하나 소개하겠습니다.
2. Why? (원인)
- X
3. How? (해결책)
소스 코드는 아래와 같은 key-finder를 활용하겠습니다. 아래는 Krumhansl-Schmuckler key-finding 알고리즘을 활용해 키를 찾아내는 코드입니다.
** https://github.com/jackmcarthur/musical-key-finder
그럼 이제 활용해보겠습니다. 먼저 소스를 아래와 같이 clone한 뒤에 해당 폴더에서 작업하겠습니다.
git clone https://github.com/jackmcarthur/musical-key-finder.git
keyfinder.py라는 파일을 import해서 사용하겠습니다. 코드는 아래와 같습니다.
- 0sec~22sec에서 어느 pitch class가 가장 많이 보이는 지를 프린트합니다.
- 0sec~22sec에서 어떤 키가 가장 가능성이 높은지를 프린트합니다.
- 22sec~33sec에서 어떤 키가 가장 가능성이 높은지를 프린트합니다.
import librosa
from keyfinder import Tonal_Fragment
listm= ["test_a.mp3",
"./test_b.mp3",
"./test_c.mp3",
"./test_d.mp3"]
for audio_path in listm:
print("finding ... {}".format(audio_path))
y, sr = librosa.load(audio_path)
y_harmonic, y_percussive = librosa.effects.hpss(y)
print("===============================")
tonal_frag = Tonal_Fragment(y_harmonic, sr, tend=22)
tonal_frag.print_chroma()
print("===============================")
tonal_frag.print_key()
print("===============================")
tonal_frag = Tonal_Fragment(y_harmonic, sr, tstart=22, tend=33)
tonal_frag.print_key()
예시 결과는 아래와 같습니다
finding ... ./test_a.mp3
===============================
C 0.557
C# 0.492
D 0.463
D# 0.599
E 0.385
F 0.354
F# 0.496
G 0.579
G# 1.000
A 0.665
A# 0.947
B 0.974
===============================
likely key: G# minor, correlation: 0.667
===============================
likely key: G# minor, correlation: 0.752
'Developers 공간 [Shorts] > Vision & Audio' 카테고리의 다른 글
[Generative] Llama 활용해 이미지에 대한 captioning, tagging하기 (2) | 2024.12.27 |
---|---|
[Generative] Huggingface 데이터 받아 사용하기 (0) | 2024.12.12 |
[Data Science] Embedding을 2차원 Visualize하기 (0) | 2024.11.10 |
[Generative] Python으로 FID 구하기 (0) | 2024.10.15 |
[Audio] Python Pedalboard를 활용해 Audio를 바꾸기 (2) | 2024.10.10 |