이 예제는 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 아이콘을 클릭하세요. 목록에서 본인의 모바일 기기를 선택하면, 기기 화면에 아래와 같은 기본 화면이 표시됩니다.

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