Я хотел бы начать с отказа от ответственности, что я очень новичок в Android Studio и Java Script, и программирование даже не является моей сильной стороной. Тем не менее, я пытаюсь разработать приложение для синтезатора звука, и, хотя я могу заставить все работать, я не могу заставить звук транслироваться. По сути, я могу использовать AudioTrack в статическом режиме для воспроизведения рассчитанных звуковых волн продолжительностью до 10 секунд, однако я не могу динамически воспроизводить несколько нажатий клавиш (в приложении я настроил 25-клавишную клавиатуру с 2 октавами), и я не могу удерживать вниз ключ в течение длительного времени либо. У меня есть ползунок длины, который регулирует продолжительность воспроизводимой ноты от 0,1 до 10 секунд. Я хотел бы иметь возможность нажимать несколько клавиш одновременно, а также удерживать клавишу в течение длительного периода времени и чтобы приложение непрерывно выводило звук. Я провел некоторое исследование, и кажется, что лучший способ добиться этого — использовать потоковый режим библиотеки AudioTrack и использовать потоки? Я очень не знаком ни с библиотекой, ни с потоками, ни даже с языком.
Я следовал руководству по потоковой передаче звука, предоставленному здесь, за исключением того, что я пробовал немного другой подход, который, как мне кажется, лучше сработает в моем случае. Я разместил свой тестовый код ниже (обратите внимание, что это не весь мой код для воспроизведения разных звуков и тому подобного, а вместо этого только самый минимум с одной настройкой клавиши (c4), и я пытаюсь заставить его непрерывно воспроизводить звук. Когда я впервые нажимаю клавишу, он воспроизводит звук до тех пор, пока я удерживаю клавишу. Однако после того, как я отпускаю клавишу и нажимаю ее снова, приложение просто вылетает. Я не совсем уверен, почему это Я пробовал разные вещи, такие как вызов функции audioThread.start() только один раз или попытку остановить поток, но безуспешно. Если бы я вызвал функцию audioThread.start() только один раз, приложение не вылетает, когда я снова нажимаю клавишу, но он также не воспроизводит звук. Когда он воспроизводит звук, он вылетает из приложения, если я нажимаю клавишу второй раз.
Я также полностью описал свою проблему выше, потому что я не уверен, что использование потоков - лучший способ сделать это. В идеале хотелось бы, чтобы я мог нажимать любую из 25 клавиш на клавиатуре, а аудиотека стримила бы звуки для одновременно нажатых клавиш, а не выводила ничего, если ничего не нажималось. Мне не нравится идея запуска 25 разных потоков, потому что мой звуковой буфер настраивается в каждом потоке, и я думаю, что предыдущий буфер будет перезаписан, если я воспроизведу несколько нот одновременно? Пожалуйста, дайте мне знать, если вы думаете, что я иду в неправильном направлении, используя потоки для приложения, к которому я стремлюсь. Я думал, что потоки будут лучше, потому что мне нужно выполнить много вычислений перед потоковой передачей аудио (макс. 25 x 6 x 3 = 450 триггерных операций для расчета одного образца моей формы волны), и поэтому я подумал, что каким-то образом конвейеризация вычислений позволит будь лучше?
В любом случае, пожалуйста, дайте мне знать, почему я не могу заставить тестовую установку воспроизводить звук, когда я нажимаю клавишу во второй раз? Я также использую Lenovo tabM10 FHD Plus, если это актуальная информация. Это также мой первый раз, когда я использую stackOverflow, поэтому я извиняюсь, если я проделал ужасную работу по форматированию своего сообщения. Если вы считаете, что я должен отредактировать свой пост, чтобы быть более кратким / ясным в отношении моей проблемы, сообщите мне, и я это исправлю. Я заранее приношу извинения за неудобства.
Мой тестовый код:
package com.example.ece496_simplesynth;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.MotionEventCompat;
import android.graphics.Color;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Build;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private AudioTrack audioTrack;
private int intBufferSize;
private short[] shortAudioData;
private boolean isActive = false;
private Thread audioThread;
private boolean keyPress = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final View c4 = (View) findViewById(R.id.c4);
c4.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int action = motionEvent.getAction();//.getActionMasked(motionEvent);
if (action == MotionEvent.ACTION_DOWN) {
c4.setBackgroundColor(Color.parseColor("#ed1b24")); //"#81DAF5"
keyPress = true;
audioThread.start();
}
else if (action == MotionEvent.ACTION_UP) {
c4.setBackgroundColor(Color.parseColor("#FFFFFF"));
keyPress = false;
//audioThread.stop();
}
return true;
}
});
audioThread = new Thread(new Runnable() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void run() {
threadLoop();
}
});
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void threadLoop(){
int intSampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
intBufferSize = AudioTrack.getMinBufferSize(intSampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
shortAudioData = new short[intBufferSize];
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
intSampleRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
intBufferSize,
AudioTrack.MODE_STREAM);
audioTrack.setPlaybackRate(intSampleRate);
int n = 0;
float x;
float TS = 1.0f/intSampleRate;
float freq = 440.0f;
float PI = 3.14159f;
float omega = 2.0f*PI*freq*TS;
if(keyPress){
audioTrack.play();
}
while(keyPress){
for(int i = 0; i < shortAudioData.length; ++i){
if(n == Integer.MAX_VALUE | n < 0){
n = 0;
}
x = (float)(Math.sin((float)(omega*n)));
++n;
shortAudioData[i] = (short)(x * Short.MAX_VALUE);
}
audioTrack.write(shortAudioData, 0, shortAudioData.length);
}
audioTrack.stop();
}
}
intBufferSize
,shortAudioData
,audioTrack
, поэтому, когда вы нажимаете одну клавишу, он запускает цикл потока и, например, устанавливает дорожку autio, но когда вы нажимаете следующую клавишу, он запускает другой цикл потока. и перезаписать предыдущую звуковую дорожку во время ее воспроизведения. Рассмотрите возможность перемещения ранее упомянутых переменных внутри методаthreadLoop
. - person sorifiend   schedule 11.03.2021audioThread
, но каждое нажатие клавиши пытается снова запустить поток, это не сработает так, как вы предполагали. Вам либо нужно создавать новый поток каждый раз, когда нажимается клавиша, либо вам нужно использовать один поток для управления списком звуков/клавиш для воспроизведения и т. д. - person sorifiend   schedule 11.03.2021