【发布时间】:2017-07-24 04:23:30
【问题描述】:
我正在使用 TarsosDSP 实时计算音高频率。它使用实现 Runnable 的 AudioDispatcher 并通过 handlePitch 方法发布结果以在主线程中使用。
我正在使用 SurfaceView 在更新时绘制此值。 SurfaceView 还需要另一个线程在画布上绘制。所以我有 2 个可运行的对象。我无法管理如何通过一个线程更新表面视图,同时从另一个线程(audiodispatcher)获取音高值。
我只想使用我在 handlePitch() 方法中获得的 cent 值来更新我在 surfaceview 上的绘图。但是我的应用程序冻结了。有什么想法吗?
在 MainAcitivity.java (onCreate(...))
myView = (MySurfaceView) findViewById(R.id.myview);
int sr = 44100;//The sample rate
int bs = 2048;
AudioDispatcher d = AudioDispatcherFactory.fromDefaultMicrophone(sr,bs,0);
PitchDetectionHandler printPitch = new PitchDetectionHandler() {
@Override
public void handlePitch(final PitchDetectionResult pitchDetectionResult, AudioEvent audioEvent) {
final float p = pitchDetectionResult.getPitch();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (p != -1){
float cent = (float) (1200*Math.log(p/8.176)/Math.log(2)) % 12;
System.out.println(cent);
myView.setCent(cent);
}
}
});
}
};
PitchProcessor.PitchEstimationAlgorithm algo = PitchProcessor.PitchEstimationAlgorithm.YIN; //use YIN
AudioProcessor pitchEstimator = new PitchProcessor(algo, sr,bs,printPitch);
d.addAudioProcessor(pitchEstimator);
d.run();//starts the dispatching process
AudioProcessor p = new PitchProcessor(algo, sr, bs, printPitch);
d.addAudioProcessor(p);
new Thread(d,"Audio Dispatcher").start();
在 SurfaceView.java 中(以下代码由构造函数触发)
myThread = new MyThread(this);
surfaceHolder = getHolder();
bmpIcon = BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher);
iconWidth = bmpIcon.getWidth();
iconHeight = bmpIcon.getHeight();
density = getResources().getDisplayMetrics().scaledDensity;
setLabelTextSize(Math.round(DEFAULT_LABEL_TEXT_SIZE_DP * density));
surfaceHolder.addCallback(new SurfaceHolder.Callback(){
@Override
public void surfaceCreated(SurfaceHolder holder) {
myThread.setRunning(true);
myThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
myThread.setRunning(false);
while (retry) {
try {
myThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}});
protected void drawSomething(Canvas canvas) {
updateCanvas(canvas, this.cent); //draws some lines depending on the cent value
}
public void setCent(double cent) {
if (this.cent > maxCent)
this.cent = maxCent;
this.cent = cent;
}
更新:
MyThread.java
public class MyThread extends Thread {
MySurfaceView myView;
private boolean running = false;
public MyThread(MySurfaceView view) {
myView = view;
}
public void setRunning(boolean run) {
running = run;
}
@Override
public void run() {
while(running){
Canvas canvas = myView.getHolder().lockCanvas();
if(canvas != null){
synchronized (myView.getHolder()) {
myView.drawSomething(canvas);
}
myView.getHolder().unlockCanvasAndPost(canvas);
}
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
【问题讨论】:
-
一件事:在
setCent中,if应该在分配之后进行。其他的:你的MyThread打电话给drawSomething了吗? -
感谢 setCent。我添加了 MyThread.java 文件。它调用drawSomething。问题是如何使用我通过 handlePitch 事件获得的分值。
-
该值应该是 volatile 或使用 getter 访问,以便您获得该值的正确副本
标签: android multithreading surfaceview tarsosdsp