마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

실시간 음성 제어 fft 질문드립니다.

0 추천
 
import android.app.Activity; 
import android.graphics.Bitmap; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.media.AudioFormat; 
import android.media.AudioRecord; 
import android.media.MediaRecorder; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.ImageView; 
import ca.uol.aig.fftpack.RealDoubleFFT; 
 
// FFT(Fast Fourier Transform) DFT 알고리즘 : 데이터를 시간 기준(time base)에서 주파수 기준(frequency base)으로 바꾸는데 사용. 
public class AudioProcessing extends Activity implements OnClickListener { 
// AudioRecord 객체에서 주파수는 8kHz, 오디오 채널은 하나, 샘플은 16비트를 사용 
int frequency = 8000; 
/*@SuppressWarnings({"unchecked", "deprecation"})*/ 
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; 
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; 
// 우리의 FFT 객체는 transformer고, 이 FFT 객체를 통해 AudioRecord 객체에서 한 번에 256가지 샘플을 
// 다룬다. 사용하는 샘플의 수는 FFT 객체를 통해 
// 샘플들을 실행하고 가져올 주파수의 수와 일치한다. 다른 크기를 마음대로 지정해도 되지만, 메모리와 성능 측면을 반드시 고려해야 
// 한다. 
// 적용될 수학적 계산이 프로세서의 성능과 밀접한 관계를 보이기 때문이다. 
private RealDoubleFFT transformer; 
int blockSize = 256; 
Button startStopButton; 
boolean started = false; 
 
// RecordAudio는 여기에서 정의되는 내부 클래스로서 AsyncTask를 확장한다. 
RecordAudio recordTask; 
 
// Bitmap 이미지를 표시하기 위해 ImageView를 사용한다. 이 이미지는 현재 오디오 스트림에서 주파수들의 레벨을 나타낸다. 
// 이 레벨들을 그리려면 Bitmap에서 구성한 Canvas 객체와 Paint객체가 필요하다. 
ImageView imageView; 
Bitmap bitmap; 
Canvas canvas; 
Paint paint; 
 
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.main); 
 
startStopButton = (Button) findViewById(R.id.StartStopButton); 
startStopButton.setOnClickListener(this); 
 
// RealDoubleFFT 클래스 컨스트럭터는 한번에 처리할 샘플들의 수를 받는다. 그리고 출력될 주파수 범위들의 수를 
// 나타낸다. 
transformer = new RealDoubleFFT(blockSize); 
 
// ImageView 및 관련 객체 설정 부분 
imageView = (ImageView) findViewById(R.id.ImageView01); 
bitmap = Bitmap.createBitmap((int) 256, (int) 100, 
Bitmap.Config.ARGB_8888); 
canvas = new Canvas(bitmap); 
paint = new Paint(); 
paint.setColor(Color.GREEN); 
imageView.setImageBitmap(bitmap); 
} 
 
// 이 액티비티의 작업들은 대부분 RecordAudio라는 클래스에서 진행된다. 이 클래스는 AsyncTask를 확장한다. 
// AsyncTask를 사용하면 사용자 인터페이스를 멍하니 있게 하는 메소드들을 별도의 스레드로 실행한다. 
// doInBackground 메소드에 둘 수 있는 것이면 뭐든지 이런 식으로 실행할 수 있다. 
private class RecordAudio extends AsyncTask<Void, double[], Void> { 
@Override
protected Void doInBackground(Void... params) { 
try { 
// AudioRecord를 설정하고 사용한다. 
int bufferSize = AudioRecord.getMinBufferSize(frequency, 
channelConfiguration, audioEncoding); 
 
AudioRecord audioRecord = new AudioRecord( 
MediaRecorder.AudioSource.MIC, frequency, 
channelConfiguration, audioEncoding, bufferSize); 
 
// short로 이뤄진 배열인 buffer는 원시 PCM 샘플을 AudioRecord 객체에서 받는다. 
// double로 이뤄진 배열인 toTransform은 같은 데이터를 담지만 double 타입인데, FFT 
// 클래스에서는 double타입이 필요해서이다. 
short[] buffer = new short[blockSize]; 
double[] toTransform = new double[blockSize]; 
 
audioRecord.startRecording(); 
 
while (started) { 
int bufferReadResult = audioRecord.read(buffer, 0, 
blockSize); 
 
// AudioRecord 객체에서 데이터를 읽은 다음에는 short 타입의 변수들을 double 타입으로 
// 바꾸는 루프를 처리한다. 
// 직접 타입 변환(casting)으로 이 작업을 처리할 수 없다. 값들이 전체 범위가 아니라 -1.0에서 
// 1.0 사이라서 그렇다 
// short를 32,768.0(Short.MAX_VALUE) 으로 나누면 double로 타입이 바뀌는데, 
// 이 값이 short의 최대값이기 때문이다. 
for (int i = 0; i < blockSize && i < bufferReadResult; i++) { 
toTransform[i] = (double) buffer[i] / Short.MAX_VALUE; // 부호 
// 있는 
// 16비트 
} 
 
// 이제 double값들의 배열을 FFT 객체로 넘겨준다. FFT 객체는 이 배열을 재사용하여 출력 값을 
// 담는다. 포함된 데이터는 시간 도메인이 아니라 
// 주파수 도메인에 존재한다. 이 말은 배열의 첫 번째 요소가 시간상으로 첫 번째 샘플이 아니라는 얘기다. 
// 배열의 첫 번째 요소는 첫 번째 주파수 집합의 레벨을 나타낸다. 
 
// 256가지 값(범위)을 사용하고 있고 샘플 비율이 8,000 이므로 배열의 각 요소가 대략 
// 15.625Hz를 담당하게 된다. 15.625라는 숫자는 샘플 비율을 반으로 나누고(캡쳐할 수 있는 
// 최대 주파수는 샘플 비율의 반이다. <- 누가 그랬는데...), 다시 256으로 나누어 나온 것이다. 
// 따라서 배열의 첫 번째 요소로 나타난 데이터는 영(0)과 15.625Hz 사이에 
// 해당하는 오디오 레벨을 의미한다. 
transformer.ft(toTransform); 
// publishProgress를 호출하면 onProgressUpdate가 호출된다. 
publishProgress(toTransform); 
} 
 
audioRecord.stop(); 
} catch (Throwable t) { 
Log.e("AudioRecord", "Recording Failed"); 
} 
 
return null; 
}
소스에서
 
int frequency = 8000;
부분이 음성대역인 ~4000Hz를 위해 8000이었는데요,
음성뿐만이 아니라 음악과같이 더 다양한 주파수대역을 해보려고 이 값을 바꿔보았는데요, 그러면 실행이 안되네요 ㅠㅠ
혹시 범위가 초과되었을까봐 큰폭으로 조정하지 않기도 했는데도 8000이 아니면 실행되지않네요.. 8000으로하면 되구요
뭐가문제일까요..?
 
타라가 (320 포인트) 님이 2015년 5월 18일 질문

답변 달기

· 글에 소스 코드 보기 좋게 넣는 법
· 질문에 대해 추가적인 질문이나 의견이 있으면 답변이 아니라 댓글로 달아주시기 바랍니다.
표시할 이름 (옵션):
개인정보: 당신의 이메일은 이 알림을 보내는데만 사용됩니다.
스팸 차단 검사:
스팸 검사를 다시 받지 않으려면 로그인하거나 혹은 가입 하세요.
...