Computer >> 컴퓨터 >  >> 프로그래밍 >> Android

Android에서 임의의 톤(Tone)을 재생하는 방법 – AudioTrack 활용 가이드

이 예제는 Android에서 AudioTrack 클래스를 사용하여 임의의 톤(음성 신호)을 직접 생성하고 재생하는 방법을 보여줍니다. 오디오 파일 없이 순수하게 수학적 계산만으로 소리를 만들어내는 원리를 단계별로 살펴보겠습니다.

1단계 – 새 프로젝트 생성

Android Studio를 실행한 후 File ⇒ New Project 메뉴로 이동하여 새 프로젝트를 생성합니다. 필요한 모든 세부 정보를 입력하고 프로젝트 설정을 완료하세요.

2단계 – 레이아웃 파일 작성 (res/layout/activity_main.xml)

아래 코드를 res/layout/activity_main.xml에 추가합니다. 화면 중앙에 음악 아이콘과 안내 문구가 표시되도록 구성했습니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">
    <ImageView
        android:layout_width="200dp"
        android:layout_height="300dp"
        android:src="@drawable/ic_music_note_black_24dp"/>
    <TextView
        android:text="Increase the emulator Volume, Listen to the arbitrary tone!"
        android:textSize="16sp"
        android:textStyle="bold|italic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

3단계 – 메인 액티비티 작성 (src/MainActivity.java)

핵심 로직이 담긴 코드입니다. genTone() 메서드에서 440Hz 주파수의 사인파(sine wave) 샘플을 생성하고, playSound() 메서드에서 AudioTrack을 통해 실제로 소리를 출력합니다.

import androidx.appcompat.app.AppCompatActivity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.os.Handler;
public class MainActivity extends AppCompatActivity {
    private final int duration = 10;
    private final int sampleRate = 8000;
    private final int numSamples = duration * sampleRate;
    private final double[] sample = new double[numSamples];
    private final byte[] generatedSnd = new byte[2 * numSamples];
    Handler handler = new Handler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    protected void onResume() {
        super.onResume();
        final Thread thread = new Thread(new Runnable() {
            public void run() {
                genTone();
                handler.post(new Runnable() {
                    public void run() {
                        playSound();
                    }
                });
            }
        });
        thread.start();
    }
    void genTone(){
        for (int i = 0; i < numSamples; ++i) {
            double freqOfTone = 440;
            sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/ freqOfTone));
        }
        int idx = 0;
        for (final double dVal : sample) {
            final short val = (short) ((dVal * 32767));
            generatedSnd[idx++] = (byte) (val & 0x00ff);
            generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
        }
    }
    void playSound(){
        final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
        sampleRate, AudioFormat.CHANNEL_OUT_MONO,
        AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
        AudioTrack.MODE_STATIC);
        audioTrack.write(generatedSnd, 0, generatedSnd.length);
        audioTrack.play();
    }
}

코드의 주요 포인트는 다음과 같습니다.

  • duration(10초) × sampleRate(8000Hz)로 총 샘플 수를 계산합니다.
  • Math.sin() 함수를 이용해 440Hz(표준 음 A4) 사인파를 생성합니다.
  • 생성된 double 값을 16비트 PCM 형식의 byte 배열로 변환합니다.
  • 오디오 생성은 백그라운드 스레드에서 처리하여 UI 스레드의 부하를 줄입니다.

4단계 – 매니페스트 파일 수정 (androidManifest.xml)

아래 코드를 androidManifest.xml에 추가합니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.com.sample">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    </application>
</manifest>

앱 실행하기

이제 애플리케이션을 실행해 보겠습니다. 실제 Android 기기가 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤, 툴바의 Run 아이콘을 클릭하세요. 목록에서 본인의 모바일 기기를 선택하면, 기기 화면에 아래와 같은 기본 화면이 표시됩니다.

Android에서 임의의 톤(Tone)을 재생하는 방법 – AudioTrack 활용 가이드

에뮬레이터 또는 실제 기기의 미디어 볼륨을 높이면 10초 동안 440Hz의 일정한 톤이 재생되는 것을 들을 수 있습니다. freqOfTone 값을 변경하면 다양한 주파수의 소리를 실험해볼 수 있으니, 간단한 신호 발생기나 경고음 앱을 만들 때 유용하게 활용해 보세요.