๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Study/Android

[์•ˆ๋“œ๋กœ์ด๋“œ ์ฝ”ํ‹€๋ฆฐ] 12. ์‹ค์ „ํ”„๋กœ์ ํŠธ(5) - ์‹ค๋กœํฐ

์‹ค์ „ ํ”„๋กœ์ ํŠธ

์‹ค์Šต - ์†์ „๋“ฑ

์ฃผ์š”๊ตฌ์„ฑ

- ๊ฐ€๋กœํ™”๋ฉด์œผ๋กœ ๊ณ ์ •๋œ ํ•œ ์•กํ‹ฐ๋น„ํ‹ฐ์— ๋„, ๋ ˆ, ๋ฏธ, ํŒŒ, ์†”, ๋ผ, ์‹œ, ๋„ ์ŒํŒ์ด ์žˆ์Œ

- ์ŒํŒ์„ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น ์Œ์ด ์žฌ์ƒ๋จ

    - ์ŒํŒ์€ ํ…์ŠคํŠธ ๋ทฐ ์†์„ฑ์„ ์ˆ˜์ •ํ•˜๊ณ , ์†Œ๋ฆฌ๋Š” SoundPool ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์žฌ์ƒํ•จ

- SoundPool์€ ์•ˆ๋“œ๋กœ์ด๋“œ 5.0๋ถ€ํ„ฐ ์‚ฌ์šฉ๋ฒ•์ด ๋‹ฌ๋ผ์ง

    - ๊ตฌ ๋ฒ„์ „๊ณผ ์‹  ๋ฒ„์ „๊ธฐ๊ธฐ์—์„œ ๋ชจ๋‘ ์ž˜ ๋™์ž‘ํ•˜๋„๋ก ๋ฒ„์ „ ๋ถ„๊ธฐ๋ฅผ ์ ์šฉํ•จ

 

1. ๋ ˆ์ด์•„์›ƒ ์ž‘์„ฑ

๊ฐ€๋กœ ๋ชจ๋“œ๋กœ ๊ณ ์ •ํ•˜๊ธฐ

๋ฐฉ๋ฒ•1) MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // ํ™”๋ฉด์ด ๊ฐ€๋กœ ๋ชจ๋“œ๋กœ ๊ณ ์ •๋˜๊ฒŒ ํ•˜๊ธฐ ์ฒซ๋ฒˆ์งธ ๋ฐฉ๋ฒ•
        //requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

 

๋ฐฉ๋ฒ•2) AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
       ...
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:screenOrientation="landscape">
        ...
        </activity>
    </application>

</manifest>

 

๊ฐ€๋กœ ๋ชจ๋“œ๋กœ ๊ณ ์ •ํ•˜๊ธฐ 

- ๋ ˆ์ด์•„์›ƒ ์—๋””ํ„ฐ์—์„œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ๊ฐ€๋กœ ๋ชจ๋“œ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•จ

- activity_main.xml ํŒŒ์ผ์„ ์—ด๊ณ  ๋ ˆ์ด์•„์›ƒ ์—๋””ํ„ฐ๋ฅผ ๊ฐ€๋กœ ๋ชจ๋“œ๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋„๋ก โ‘  Orientation for Preview๋ฅผ ํด๋ฆญํ•˜์—ฌ โ‘ก Landscape๋ฅผ ์„ ํƒํ•จ

 

ํƒ€์ด๋ธ” ๋ฐ” ์—†์• ๊ธฐ

- AndoridManifest.xml : ํ…Œ๋งˆ(theme)๊ฐ€ ๋ชจ์–‘ ๊ฒฐ์ •

        android:theme="@style/Theme.Xylophone"

- Res/values/themes/themes.xml → .noActionBar

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Base.Theme.Xylophone" parent="Theme.Material3.DayNight.NoActionBar">
        <!-- Customize your light theme here. -->
        <!-- <item name="colorPrimary">@color/my_light_primary</item> -->
    </style>

    <style name="Theme.Xylophone" parent="Base.Theme.Xylophone" />
</resources>

 

ํ…์ŠคํŠธ ๋ทฐ๋กœ ์ŒํŒ ๋งŒ๋“ค๊ธฐ

 

2. ์†Œ๋ฆฌ ์žฌ์ƒํ•˜๊ธฐ

์‹ค๋กœํฐ ์†Œ๋ฆฌ ํŒŒ์ผ ์ค€๋น„ํ•˜๊ธฐ 

- ์‹ค๋กœํฐ ์†Œ๋ฆฌ ํŒŒ์ผ์„ http://bit.ly/2K9dQjo ์—์„œ ๋‹ค์šด๋กœ๋“œ๋ฐ›์Œ 03 STEP

 

raw ๋ฆฌ์†Œ์Šค ๋””๋ ‰ํ† ๋ฆฌ ์ถ”๊ฐ€

- Resource type ๋“œ๋กญ๋‹ค์šด ๋ฆฌ์ŠคํŠธ๋ฅผ ํด๋ฆญํ•˜์—ฌ raw๋ฅผ ์„ ํƒํ•˜๊ณ  OK๋ฅผ ํด๋ฆญํ•จ

 

raw ๋ฆฌ์†Œ์Šค ๋””๋ ‰ํ† ๋ฆฌ ์ถ”๊ฐ€

- ํ”„๋กœ์ ํŠธ ์ฐฝ์—์„œ raw ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์„ ํƒํ•˜๊ณ  ๋‹จ์ถ•ํ‚ค ๋ฅผ ๋ˆ„๋ฆ„

- ๋ถ™์—ฌ๋„ฃ์„ ํŒŒ์ผ ์ด๋ฆ„์„ ์ˆ˜์ •ํ•˜๋Š” ํ™”๋ฉด์ด ํ‘œ์‹œ๋˜๋Š”๋ฐ ์—ฌ๊ธฐ์„œ๋Š” ๊ทธ๋Œ€๋กœ OK๋ฅผ ํด๋ฆญํ•จ

- raw ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์‹ค๋กœํฐ ์†Œ๋ฆฌ ํŒŒ์ผ์„ ๋ถ™์—ฌ๋„ฃ๊ธฐ๋งŒ ํ•˜๋ฉด ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋จ

 

์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ์†Œ๋ฆฌ๋ฅผ ์žฌ์ƒํ•˜๋Š” ๋ฐฉ๋ฒ•

- MediaPlayer ํด๋ž˜์Šค์™€ SoundPool ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Œ

- MediaPlayer ํด๋ž˜์Šค๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์†Œ๋ฆฌ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์žฌ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ๋˜๋Š” ๋…ธ๋ž˜๋‚˜ ๋ฐฐ๊ฒฝ์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” ์œ ์šฉํ•จ 

- SoundPool์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•จ

 

- load ( ) ๋ฉ”์„œ๋“œ์™€ play ( ) ๋ฉ”์„œ๋“œ์˜ ์›ํ˜•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Œ

 

SoundPool ์ดˆ๊ธฐํ™” ๋ฒ„์ „ ๋ถ„๊ธฐ 

- MainActivity ํŒŒ์ผ์„ ์—ด๊ณ  SoundPool ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ์ฝ”๋“œ ์ถ”๊ฐ€

class MainActivity : AppCompatActivity() {

    private val soundPool = SoundPool.Builder().setMaxStreams(8).build()    // SoundPool ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”
    
    ...
}

 

์ŒํŒ์— ๋™์ ์œผ๋กœ ํด๋ฆญ ์ด๋ฒคํŠธ ์ •์˜ํ•˜๊ธฐ

- ๋จผ์ € listOf ( ) ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…์ŠคํŠธ ๋ทฐ์˜ ID์™€ ์Œ์› ํŒŒ์ผ์˜ ๋ฆฌ์†Œ์Šค ID๋ฅผ ์—ฐ๊ด€ ์ง€์€ Pair ๊ฐ์ฒด 8๊ฐœ๋ฅผ ๋ฆฌ์ŠคํŠธ ๊ฐ์ฒด sounds๋กœ ๋งŒ๋“ฆ 

- Pair ํด๋ž˜์Šค๋Š” ๋‘ ๊ฐœ์˜ ์—ฐ๊ด€๋œ ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•จ

- Pair(first, second) : first์™€ second, ๊ฐ๊ฐ์˜ ๊ฐ์ฒด๋ฅผ ์—ฐ๊ฒฐํ•ด ํ•œ ์Œ์œผ๋กœ ๋งŒ๋“ค์–ด์คŒ

class MainActivity : AppCompatActivity() {

    private val soundPool = SoundPool.Builder().setMaxStreams(8).build()    // SoundPool ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”

    private val sounds = listOf(        // ์‚ฌ์šฉํ•  ์Œ์›๋“ค์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋งŒ๋“ค๊ธฐ
        Pair(R.id.do1, R.raw.do1),       // (์œ„์ ฏ ์•„์ด๋””, ์‚ฌ์šฉํ•  ์Œ์›)
        Pair(R.id.re, R.raw.re),
        Pair(R.id.mi, R.raw.mi),
        Pair(R.id.fa, R.raw.fa),
        Pair(R.id.sol, R.raw.sol),
        Pair(R.id.la, R.raw.la),
        Pair(R.id.si, R.raw.si),
        Pair(R.id.do2, R.raw.do2)
    )

    ...
}

 

์ŒํŒ์— ๋™์ ์œผ๋กœ ํด๋ฆญ ์ด๋ฒคํŠธ ์ •์˜ํ•˜๊ธฐ 

- sounds ๋ฆฌ์ŠคํŠธ๋ฅผ forEach ( ) ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์†Œ๋ฅผ ํ•˜๋‚˜์”ฉ ๊บผ๋‚ด์„œ tune( ) ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌํ•จ

 

์ŒํŒ์— ๋™์ ์œผ๋กœ ํด๋ฆญ ์ด๋ฒคํŠธ ์ •์˜ํ•˜๊ธฐ

- tune ( ) ๋ฉ”์„œ๋“œ๋Š” Pair ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์„œ load ( ) ๋ฉ”์„œ๋“œ๋กœ ์Œ์›์˜ ID๋ฅผ ์–ป๊ณ , findViewById( ) ๋ฉ”์„œ๋“œ๋กœ ํ…์ŠคํŠธ ๋ทฐ์˜ ID์— ํ•ด๋‹นํ•˜๋Š” ๋ทฐ๋ฅผ ์–ป๊ณ , ํ…์ŠคํŠธ ๋ทฐ๋ฅผ ํด๋ฆญํ–ˆ์„๋•Œ ์Œ์›์„ ์žฌ์ƒํ•จ

- ์•ฑ์„ ์ข…๋ฃŒํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ release ( ) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ SoundPool ๊ฐ์ฒด์˜ ์ž์›์„ ํ•ด์ œํ•จ

class MainActivity : AppCompatActivity() {

    ...

    override fun onCreate(savedInstanceState: Bundle?) {
        // ํ™”๋ฉด์ด ๊ฐ€๋กœ ๋ชจ๋“œ๋กœ ๊ณ ์ •๋˜๊ฒŒ ํ•˜๊ธฐ ์ฒซ๋ฒˆ์งธ ๋ฐฉ๋ฒ•
        //requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        sounds.forEach { turn(it) }
    }

    private fun turn(pair: Pair<Int, Int>) {
        // ํ”Œ๋ ˆ์ด ์ „ soundPool ๊ฐ์ฒด load
        val soundId = soundPool.load(this, pair.second, 1)      // pair์˜ ๋‘๋ฒˆ์งธ(์Œ์›), 1: ์šฐ์„ ์ˆœ์œ„

        // ํด๋ฆญ ์‹œ ํ”Œ๋ ˆ์ดํ•˜๊ธฐ (Pair์˜ ์ฒซ๋ฒˆ์งธ -> ์•„์ด๋””์ด๋ฏ€๋กœ ๋ฐ”๋กœ ๋ถˆ๋Ÿฌ ์™€์„œ ์‚ฌ์šฉ)
        findViewById<TextView>(pair.first).setOnClickListener {
            soundPool.play(soundId, 1.0f, 1.0f, 0, 0, 1.0f)     // (์–ด๋–ค id, ์™ผ์ชฝ๋ณผ๋ฅจ, ์˜ค๋ฅธ์ชฝ๋ณผ๋ฅจ, ์šฐ์„ ์ˆœ์œ„, ๋ฐ˜๋ณต, ์†๋„)
        }
    }

    override fun onDestroy() {  // ์•ฑ ์ข…๋ฃŒ ์‹œ ์ž๋™์œผ๋กœ ๊ฐ์ฒด ์†Œ๋ฉธ
        super.onDestroy()
        soundPool.release()
    }
}

 

์ตœ์ข…

package com.example.xylophone

import android.media.SoundPool
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    private val soundPool = SoundPool.Builder().setMaxStreams(8).build()    // SoundPool ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”

    private val sounds = listOf(        // ์‚ฌ์šฉํ•  ์Œ์›๋“ค์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋งŒ๋“ค๊ธฐ
        Pair(R.id.do1, R.raw.do1),       // (์œ„์ ฏ ์•„์ด๋””, ์‚ฌ์šฉํ•  ์Œ์›)
        Pair(R.id.re, R.raw.re),
        Pair(R.id.mi, R.raw.mi),
        Pair(R.id.fa, R.raw.fa),
        Pair(R.id.sol, R.raw.sol),
        Pair(R.id.la, R.raw.la),
        Pair(R.id.si, R.raw.si),
        Pair(R.id.do2, R.raw.do2)
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        // ํ™”๋ฉด์ด ๊ฐ€๋กœ ๋ชจ๋“œ๋กœ ๊ณ ์ •๋˜๊ฒŒ ํ•˜๊ธฐ ์ฒซ๋ฒˆ์งธ ๋ฐฉ๋ฒ•
        //requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        sounds.forEach { turn(it) }
    }

    private fun turn(pair: Pair<Int, Int>) {
        // ํ”Œ๋ ˆ์ด ์ „ soundPool ๊ฐ์ฒด load
        val soundId = soundPool.load(this, pair.second, 1)      // pair์˜ ๋‘๋ฒˆ์งธ(์Œ์›), 1: ์šฐ์„ ์ˆœ์œ„

        // ํด๋ฆญ ์‹œ ํ”Œ๋ ˆ์ดํ•˜๊ธฐ (Pair์˜ ์ฒซ๋ฒˆ์งธ -> ์•„์ด๋””์ด๋ฏ€๋กœ ๋ฐ”๋กœ ๋ถˆ๋Ÿฌ ์™€์„œ ์‚ฌ์šฉ)
        findViewById<TextView>(pair.first).setOnClickListener {
            soundPool.play(soundId, 1.0f, 1.0f, 0, 0, 1.0f)     // (์–ด๋–ค id, ์™ผ์ชฝ๋ณผ๋ฅจ, ์˜ค๋ฅธ์ชฝ๋ณผ๋ฅจ, ์šฐ์„ ์ˆœ์œ„, ๋ฐ˜๋ณต, ์†๋„)
        }
    }

    override fun onDestroy() {  // ์•ฑ ์ข…๋ฃŒ ์‹œ ์ž๋™์œผ๋กœ ๊ฐ์ฒด ์†Œ๋ฉธ
        super.onDestroy()
        soundPool.release()
    }
}

 

 

์ •๋ฆฌ

- ์†Œ๋ฆฌ๋ฅผ ์žฌ์ƒํ•˜๋ ค๋ฉด MediaPlayer ๋˜๋Š” SoundPool ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•จ

- ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ MediaPlayer ํด๋ž˜์Šค๊ฐ€ ๊ฐ„ํŽธํ•˜์ง€๋งŒ ์—ฐ์†์œผ๋กœ ์†Œ๋ฆฌ๋ฅผ ์žฌ์ƒํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” SoundPool ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•จ 

- ๋ทฐ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ผ ๋•Œ๋Š” forEach{ } ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ ์œผ๋กœ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Œ

 

์•ฑ ์‹œ์ž‘์‹œ ๋ฐฐ๊ฒฝ์Œ์•… - MusicPlayer

๋‚˜๋งŒ์˜ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ - ์Œ์•… ์—ฐ๊ฒฐํ•ด์„œ ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด ์Œ์•… ์žฌ์ƒ