개발자/Android

안드로이드 악기 앱 개발을 위한 AudioTrack 사용하기

지구빵집 2013. 3. 13. 12:23
반응형



개발중인 악기 앱 개발을 위해 소리를 각종 소리를 만들고, 합성하고, 분석하는 방법을 포스팅.


아래 코드는 합성된 소리를 재생한다.


먼저 Layout 파일을 보면 


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

	<Button 
    	android:layout_width="wrap_content" 
    	android:layout_height="wrap_content" 
    	android:id="@+id/StartSound" 
    	android:text="Start Sound"/>
	<Button 
    	android:layout_width="wrap_content" 
    	android:layout_height="wrap_content" 
    	android:id="@+id/EndSound" 
    	android:text="End Sound"/>
</LinearLayout>


스타트, 스톱을 실행하는 버튼 2개를 배치한다.


코드를 살펴보면 onCreate 에서 버튼 등록하고 리스너를 등록해준다.





@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_audio_main);
		
		startSound = (Button) this.findViewById(R.id.StartSound);
		startSound.setOnClickListener(this);

		endSound = (Button) this.findViewById(R.id.EndSound);
		endSound.setOnClickListener(this);

		endSound.setEnabled(false);
	}


클릭할떼 어느 버튼인지 알아서 실행해주고





public void onClick(View v) {
		if (v == startSound) {
			keepGoing = true;

			audioSynth = new AudioSynthesisTask();
			audioSynth.execute();

			endSound.setEnabled(true);
			startSound.setEnabled(false);
		} else if (v == endSound) {
			keepGoing = false;

			endSound.setEnabled(false);
			startSound.setEnabled(true);
		}
	}



실제 여기가 가장 중요한 부분으로 AsyncTask 를 확장하는 내부 클래스 AudioSynthesisTask 를 만들어준다. 

AsyncTask<Void, Void, Void> 에는 doInBackground(Void... params) 라는 메소드가 정의되어 있고, 이 메소드는 액티비티의

메인스레드와는 별도의 스레드로 무엇이든 실행해준다.





private class AudioSynthesisTask extends AsyncTask<Void, Void, Void> {
		@Override
		protected Void doInBackground(Void... params) {
			final int SAMPLE_RATE = 11025;

			int minSize = AudioTrack.getMinBufferSize(SAMPLE_RATE,
					AudioFormat.CHANNEL_CONFIGURATION_MONO,
					AudioFormat.ENCODING_PCM_16BIT);

			AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
					SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO,
					AudioFormat.ENCODING_PCM_16BIT, minSize,
					AudioTrack.MODE_STREAM);

			audioTrack.play();
			
			
			short[] buffer = {
					8130, 15752, 32695, 12253, 4329,
					-3865, -19032, -32722, -16160, -466,
					8130, 15752, 22389, 27625, 31134, 32695, 32210,
					29711, 25354, 19410, 12253, 4329, -3865, -11818, -19032,
					-25055, -29511, -32121, -32722, -31276, -27874, -22728,
					-16160, -8582, -466
				};
			
			/*short[] buffer = {
								8130, 15752, 32695, 12253, 4329,
								-3865, -19032, -32722, -16160, -466
							};*/
			/*
			short[] buffer = { 8130, 15752, 22389, 27625, 31134, 32695, 32210,
					29711, 25354, 19410, 12253, 4329, -3865, -11818, -19032,
					-25055, -29511, -32121, -32722, -31276, -27874, -22728,
					-16160, -8582, -466 };
			*/

			while (keepGoing) {
				audioTrack.write(buffer, 0, buffer.length);
			}

			return null;
		}
	}




윗부분은 오디오 트랙 설정하는 부분이고, 오디오 트랙을 실행시키고 오디오 트랙에 출력할 "소리데이터"를 계속 써주면 "소리"가 재생된다.


지금 그 소리를 찾고 있다.


전체 코드를 몽땅 아래에 올립니다.




package com.soriedu.audiosynth02;

import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class AudioMainActivity extends Activity implements OnClickListener {
	
	Button startSound;
	Button endSound;

	AudioSynthesisTask audioSynth;

	boolean keepGoing = false;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_audio_main);
		
		startSound = (Button) this.findViewById(R.id.StartSound);
		startSound.setOnClickListener(this);

		endSound = (Button) this.findViewById(R.id.EndSound);
		endSound.setOnClickListener(this);

		endSound.setEnabled(false);
	}
	
	
	@Override
	public void onPause() {
		super.onPause();
		keepGoing = false;

		endSound.setEnabled(false);
		startSound.setEnabled(true);
	}
	
	public void onClick(View v) {
		if (v == startSound) {
			keepGoing = true;

			audioSynth = new AudioSynthesisTask();
			audioSynth.execute();

			endSound.setEnabled(true);
			startSound.setEnabled(false);
		} else if (v == endSound) {
			keepGoing = false;

			endSound.setEnabled(false);
			startSound.setEnabled(true);
		}
	}
	
	private class AudioSynthesisTask extends AsyncTask<Void, Void, Void> {
		@Override
		protected Void doInBackground(Void... params) {
			final int SAMPLE_RATE = 11025;

			int minSize = AudioTrack.getMinBufferSize(SAMPLE_RATE,
					AudioFormat.CHANNEL_CONFIGURATION_MONO,
					AudioFormat.ENCODING_PCM_16BIT);

			AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
					SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO,
					AudioFormat.ENCODING_PCM_16BIT, minSize,
					AudioTrack.MODE_STREAM);

			audioTrack.play();
			
			
			short[] buffer = {
					8130, 15752, 32695, 12253, 4329,
					-3865, -19032, -32722, -16160, -466,
					8130, 15752, 22389, 27625, 31134, 32695, 32210,
					29711, 25354, 19410, 12253, 4329, -3865, -11818, -19032,
					-25055, -29511, -32121, -32722, -31276, -27874, -22728,
					-16160, -8582, -466
				};
			
			/*short[] buffer = {
								8130, 15752, 32695, 12253, 4329,
								-3865, -19032, -32722, -16160, -466
							};*/
			/*
			short[] buffer = { 8130, 15752, 22389, 27625, 31134, 32695, 32210,
					29711, 25354, 19410, 12253, 4329, -3865, -11818, -19032,
					-25055, -29511, -32121, -32722, -31276, -27874, -22728,
					-16160, -8582, -466 };
			*/

			while (keepGoing) {
				audioTrack.write(buffer, 0, buffer.length);
			}

			return null;
		}
	}

	
}




반응형