Android App 개발/chordbreaker

자연/화성/가락 단음계(Natural/Harmonic/Melodic minor)

시샐 2022. 10. 30. 15:46
    private int currentKey = 0;
    private int majorMinor = 0;
    private Paint paint;
    private Bitmap bg;
    private Canvas canvas;

 

마이너 스케일도 정리했다. 마이너에서도 메이저에서처럼 조표없는 스케일이 만들어 진다.

첫번째로 정리하는 마이너는 natual minor(자연 단음계)이다.

 

장음계의 3-4음, 7-8음 사이가 반음인 것과는 달리,

자연 단음계는 2-3음, 5-6음 사이가 반음이다.

 

단음계는 슬프고 어두운 느낌을 표현한다.

 

 

 

기존의 데이터를 사용해서 변경해 쓰는 방법도 있을 것 같지만, 여기서는 그냥 메모리를 쓰기로 했다.

새로운 배열을 정의해서 단음계를 표시한다.

 

기존의 데이터에서 3음, 6음, 7음이 한 프렛씩 내려갔다.

 

    private final static int [][][] degreeMinorArray = new int[][][] {
            // 1 to 6th string
            {{4,0,5,6,0,7,0,1,0,2,3,0,4,0},{1,0,2,3,0,4,0,5,6,0,7,0,1,0},{6,0,7,0,1,0,2,3,0,4,0,5,6,0},
                    {3,0,4,0,5,6,0,7,0,1,0,2,3,0}, {7,0,1,0,2,3,0,4,0,5,6,0,7,0}, {4,0,5,6,0,7,0,1,0,2,3,0,4,0}}, //C
            {{0,4,0,5,6,0,7,0,1,0,2,3,0,4},{0,1,0,2,3,0,4,0,5,6,0,7,0,1},{5,6,0,7,0,1,0,2,3,0,4,0,5,6},
                    {2,3,0,4,0,5,6,0,7,0,1,0,2,3}, {0,7,0,1,0,2,3,0,4,0,5,6,0,7}, {0,4,0,5,6,0,7,0,1,0,2,3,0,4}}, // C#(Db)
            ...
            {{0,5,6,0,7,0,1,0,2,3,0,4,0,5},{0,2,3,0,4,0,5,6,0,7,0,1,0,2},{0,7,0,1,0,2,3,0,4,0,5,6,0,7},
                    {0,4,0,5,6,0,7,0,1,0,2,3,0,4}, {0,1,0,2,3,0,4,0,5,6,0,7,0,1}, {0,5,6,0,7,0,1,0,2,3,0,4,0,5}}, // B
    };

 

Major/minor의 변환을 위해 키 선택열에 button을 하나 더 넣었다. 이름은 MM 쵸콜릿을 기념하기 위해 button_mm으로 했다.

                <Button
                    android:id="@+id/button_mm"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="2"
                    android:minWidth="0dp"
                    android:minHeight="0dp"
                    android:text="M/m"
                    android:textAllCaps="false" />

 

이 버튼을 누를 때마다 변하는 변수는 majorMinor로 정의했고, 전역으로 처리했다.

 

    private int currentKey = 0;
    private int majorMinor = 0;
    private Paint paint;
    private Bitmap bg;
    private Canvas canvas;

 

minor scale을 위한 array가 추가되었으므로 drawFret 함수도 변경되었다.

 

코드에서 majorMinor 변수의 값은 4 가지로 되어있다.

이것은 앞으로 harmonic minor와 melodic minor를 추가할 예정이기 때문이다.

 

degreeMajorArray등을 array로 받아 지판을 그리도록 했다.

 

private void setTextCurrentKey(int key, int major){
        TextView txtKey = findViewById(R.id.txt_cur_key);

        String strMajorMinor = "Major";
        switch(major) {
            case 0: break;
            case 1: strMajorMinor = "Natural Minor"; break;
            case 2: strMajorMinor = "Harmonic Minor"; break;
            case 3: strMajorMinor = "Melodic Minor"; break;
        }

        switch(key){
            case 0: txtKey.setText("C " + strMajorMinor); break;
            case 1: txtKey.setText("C#(Db) " + strMajorMinor); break;
            case 2: txtKey.setText("D " + strMajorMinor); break;
            case 3: txtKey.setText("D#(Eb) " + strMajorMinor); break;
            case 4: txtKey.setText("E " + strMajorMinor); break;
            case 5: txtKey.setText("F " + strMajorMinor); break;
            case 6: txtKey.setText("F#(Gb) " + strMajorMinor); break;
            case 7: txtKey.setText("G " + strMajorMinor); break;
            case 8: txtKey.setText("G#(Ab) " + strMajorMinor); break;
            case 9: txtKey.setText("A " + strMajorMinor); break;
            case 10: txtKey.setText("A#(Bb) " + strMajorMinor); break;
            case 11: txtKey.setText("B " + strMajorMinor); break;
        }
    }

 

마지막으로 MM 버튼 처리 내용이다.

 

        Button buttonMM = (Button) findViewById(R.id.button_mm) ;
        buttonMM.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (majorMinor == 3)
                    majorMinor = 0;
                else
                    majorMinor++;
                drawFret(paint, canvas, bg, currentKey,majorMinor);
                setTextCurrentKey(currentKey, majorMinor);
            }
        }) ;

 

 
 

화성/가락 단음계(Harmonic/Melodic minor)

 

Major scale(장음계)는 3음과 4음(미-파), 7음과 8음(시-도) 사이가 반음이 되는 음계이다.

 

minor scale(단음계)는 음 사이가 반음이 되는 위치가 달라지는 음계인데, 사용하는 단음계의 종류는 세가지나 된다.

 

- Natural minor scale(자연 단음계)

- Harmonic minor scale(화성 단음계)

- Melodic minor scale(가락 단음계)

 

우리가 흔히 단조라고 하면 Natural minor를 말한다.

 

Natural minor(자연 단음계)는 2음과 3음(레-미), 5음과 6음(솔-라) 사이가 반음이 되도록 한 것이다.

 

Harmonic minor(화성단음계)는 Natural minor와 동일한데,

7음(시)을 다시 올려 7음과 8음 사이를 반음이 되게 한 것이다. 따라서 2음과 3음(레-미), 5음과 6음(솔-라), 7음과 8음(시-도) 사이가 반음이 된다.

 

Melodic minor(가락 단음계)는 좀 특이해서

음이 올라가는 경우와 내려가는 경우의 반음 구성이 달라지는 음계이다.

즉 Natural minor scale과 같으나 음이 올라갈 때에는 6음과 7음을 반음을 올린다.

반대로 내려갈 때는 원래대로의 음을 사용한다.

그렇다면 중간에서 올라가려다 말거나 오르락 내리락 하면 어떻게 되는 것일까?

 

아무튼 Melodic minor는 앱의 성격상 여기서는 고려하지 않아도 될 듯하다.

따라서 M/m 버튼에 Harmonic minor만 추가하는 것으로 결정을 했다.

 

코드는 기존의 degreeMinorArray외에 Harmonic minor를 정의할 degreeHMinorArray를 추가한다.

 

이번 경우에도 기존 array를 이용하는 방법도 있을 것 같지만,

어짜피 앞으로 Mode Scale이 들어가면 새로운 Array가 5 개 정도 추가로 들어가야 하므로 건강을 위해 메모리는 더 쓰는 대신, 머리는 좀 덜 쓰는 방식으로 가기로 했다.

 

Harmonic minor의 array를 만들면서 새삼 볼 수 있는 것이 6음과 7음 사이에 0이 두 개나 생기게 된다는 점이다. 즉 한 음반 차이(증2도?)가 난다.

음이 끝나는 느낌을 주기위해 7음을 반음 올렸는데, 6음과 7음 사이가 너무 벌어져 어색하므로 다시 올라갈 때만 6음을 반음 올리는 Melodic minor를 만들었다는 얘기가 얼핏 이해가 가는 것 같기도 하다.

 

아무튼 6음과 7음 사이가 벌어져 007이 많이 보이게 되었다.

 

            {{4,0,5,6,0,0,7,1,0,2,3,0,4,0},{1,0,2,3,0,4,0,5,6,0,0,7,1,0},{6,0,0,7,1,0,2,3,0,4,0,5,6,0},
                    {3,0,4,0,5,6,0,0,7,1,0,2,3,0}, {0,7,1,0,2,3,0,4,0,5,6,0,0,7}, {4,0,5,6,0,0,7,1,0,2,3,0,4,0}}, //C(B#)

 

이 컨셉에 따라 코드를 쭉 정리했다.

 

        int [][][] array = degreeMajorArray;

        if (major == 1)
            array = degreeMinorArray;
        else if (major == 2)
            array = degreeHMinorArray;
       ...     
            
        String strMajorMinor = "Major";

        if (major == 1)
            strMajorMinor = "Natural Minor";
        else if (major == 2)
            strMajorMinor = "Harmonic Minor";
            
        ...
        
        Button buttonMM = (Button) findViewById(R.id.button_mm) ;
        buttonMM.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (majorMinor == 2)
                    majorMinor = 0;
                else
                    majorMinor++;
                drawFret(paint, canvas, bg, currentKey,majorMinor);
                setTextCurrentKey(currentKey, majorMinor);
                setTextRelativeKey(currentKey, majorMinor);
            }
        }) ;

 

 

 

 

 

반응형