java - 生成和播放声音信号
问题描述
我想创建应用程序来播放摩尔斯电码。为此,我发现您可以通过将字节数组写入 AudoTrack 对象来生成声音。但是,无论配置如何,我都听不到任何声音,即使我的日志说,我正确调用了每个函数
主班
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
Consts Cons = new Consts();
final int patternLenght = 10;
String pattern;
int[] soundArray = new int[patternLenght * 2];
MediaPlayer[] mp = new MediaPlayer[patternLenght * 2];
int userInputCorrectNumber;
private String GeneratePattern(int lenght) {
String patterngen = "";
Random rand = new Random();
for (int i = 0; i < lenght; i++) {
int n = rand.nextInt(2);
String temp = Cons.ALFABET[n];
patterngen = patterngen + temp;
}
pattern = patterngen;
return patterngen;
}
private void PlayPattern(){
BeepClassMain.SetUpEverything();
BeepClassMain.GenerateSoundWave();
String morsePat=BeepClassMain.ConvertPatternToMorsePattern(pattern);
BeepClassMain.PlayPattern(morsePat);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button start = findViewById(R.id.make_pattern);
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pattern = GeneratePattern(patternLenght);
Log.i("Pattern", pattern);
}
});
Button playpattern = findViewById(R.id.playPattern);
playpattern.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PlayPattern();
}
});
}
}
常量类
public class Consts {final String ALFABET[] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; }
BeepClassMain
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;
public class BeepClassMain {
private static AudioTrack audioTrack;
private static int SAMPLE_RATE_HZ = 48000;
private static int numofSamples;
private static short samples[];
private static short silenceTab[];
public static void SetUpEverything() {
int bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE_HZ, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE_HZ, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);
audioTrack.setStereoVolume(AudioTrack.getMaxVolume(), AudioTrack.getMaxVolume());
numofSamples = 250 * 8000 / 1000; // duration in ms * samplerate/1000
samples = new short[numofSamples];
silenceTab=new short[numofSamples];
}
public static void GenerateSoundWave() {
for (int i = 0; i < numofSamples; i++) {
samples[i] = 15000; //example numbers of generated sound
silenceTab[i]=0; //no value, silence
}
}
public static String ConvertPatternToMorsePattern(String pattern) {
String morsePattern = "";
GenerateSoundWave();
for (int i = 0; i < pattern.length(); i++) {
if (pattern.charAt(i) == 'A') morsePattern += ".- ";
if (pattern.charAt(i) == 'B') morsePattern += "-... ";
if (pattern.charAt(i) == 'C') morsePattern += "-.-. ";
if (pattern.charAt(i) == 'D') morsePattern += "-.. ";
if (pattern.charAt(i) == 'E') morsePattern += ". ";
if (pattern.charAt(i) == 'F') morsePattern += "..-. ";
if (pattern.charAt(i) == 'G') morsePattern += "--. ";
if (pattern.charAt(i) == 'H') morsePattern += ".... ";
if (pattern.charAt(i) == 'I') morsePattern += ".. ";
if (pattern.charAt(i) == 'J') morsePattern += ".--- ";
if (pattern.charAt(i) == 'K') morsePattern += "-.- ";
if (pattern.charAt(i) == 'L') morsePattern += ".-.. ";
if (pattern.charAt(i) == 'M') morsePattern += "-- ";
if (pattern.charAt(i) == 'N') morsePattern += "-. ";
if (pattern.charAt(i) == 'O') morsePattern += "--- ";
if (pattern.charAt(i) == 'P') morsePattern += ".--. ";
if (pattern.charAt(i) == 'Q') morsePattern += "--.- ";
if (pattern.charAt(i) == 'R') morsePattern += ".-. ";
if (pattern.charAt(i) == 'S') morsePattern += "... ";
if (pattern.charAt(i) == 'T') morsePattern += "- ";
if (pattern.charAt(i) == 'U') morsePattern += "..- ";
if (pattern.charAt(i) == 'V') morsePattern += "...- ";
if (pattern.charAt(i) == 'W') morsePattern += ".-- ";
if (pattern.charAt(i) == 'X') morsePattern += "-..- ";
if (pattern.charAt(i) == 'Y') morsePattern += "-.-- ";
if (pattern.charAt(i) == 'Z') morsePattern += "--.. ";
}
Log.i("patterntomorsebeep", morsePattern);
return morsePattern;
}
private static void PlayDot() {
audioTrack.write(samples, 0, 8000);
}
private static void PlaySilence(){
audioTrack.write(silenceTab,0,8000);
}
public static int isStillSameCharacter(String morsePattern, int i) {
if (morsePattern.charAt(i + 1) == '.' || morsePattern.charAt(i + 1) == '-') return 1;
else return 0;
}
public static void PlayPattern(String morsePattern) {
audioTrack.play();
for (int i = 0; i < morsePattern.length(); i++) {
if (morsePattern.charAt(i) == '.') {
PlayDot();
if (isStillSameCharacter(morsePattern, i) == 1) continue;
PlaySilence();
}
}
}
}
现在我只写了点函数和静音,因为其他角色将基于这两个函数,但是 onyl 通过将样本audioTrack.write(samples, 0, 8000*3);
数乘以播放线而不是点来增加它们的大小
解决方案
我很惊讶您没有听到咔哒声(因为从 15000 过渡到 0)。无论如何,您没有听到任何哔哔声,因为您没有将实际波形放入样本中。15000只是一条直线。尝试使用正弦波:
samples[i] = (short) (Math.sin(i*1000.0f/*Hz*//SAMPLE_RATE_HZ*Math.PI*2)*15000/*Amp*/);
每当您编写代码以在内存中生成波形时,就像这样,在调试器中检查数组是个好主意。这样你就可以确保你的数学是正确的。这个应该显示一个波,从 0 开始,在大约 +15000 和 -15000 之间波动,周期约为 44 个样本。
此外,您要确保您的声音阵列的大小至少为 8000,因为这就是您要尝试的大小write()
。确保这一行:
250 * 8000 / 1000
正在使用正确的采样率:
250 * SAMPLE_RATE_HZ / 1000
推荐阅读
- c - 使用 spidev C 读取的数据与示波器测量结果不一致
- r - 根据主键添加列
- python - 在heroku上下载图像
- reactjs - 如何在 framer.motion 中的布局动画后摆脱条纹
- redis - 如何查看我的 redis 服务器每天执行多少命令?
- xcode - 有没有一种简单的方法来下载 Firebase 存储和数据库并在开发模式下使用这些快照,而不是调用 API?
- python-3.x - 将 TextInput 更改为仅显示 Kivy Python 的函数
- python - 我必须先运行 get-item 或 set-item 命令,然后我的 winrm 远程命令才能工作
- ios - 对 UITableView 的 tableHeaderView 使用约束,tableHeaderView 出现在单元格的顶部
- gtsummary - 胶水不能将函数插入字符串。* 对象 'n' 是一个函数