<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center">
<EditText
android:id="@+id/edit_text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="输入字符 1"
android:textSize="18sp"/>
<EditText
android:id="@+id/edit_text2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="输入字符 2"
android:textSize="18sp"/>
<EditText
android:id="@+id/speed_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="输入速度(毫秒)"
android:inputType="number"
android:textSize="18sp"/>
<Button
android:id="@+id/play_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Play"
android:textSize="20sp"
android:background="@color/teal_700"
android:textColor="@android:color/white"
android:padding="12dp"
android:layout_gravity="center"/>
</LinearLayout>
package com.a.app;
/*
手机编程王APP & AIDE编译器联合出品
官方微信2133688724
微信公众号:手机编程APP
官网:www.shoujibiancheng.com
*/
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioTrack;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
class ToneInfo {
int frequency;
int duration;
public ToneInfo(int frequency, int duration) {
this.frequency = frequency;
this.duration = duration;
}
}
public class MainActivity extends AppCompatActivity {
private EditText editText1, editText2, speedInput;
private Button playButton;
private boolean isPlaying = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText1 = findViewById(R.id.edit_text1);
editText2 = findViewById(R.id.edit_text2);
speedInput = findViewById(R.id.speed_input);
playButton = findViewById(R.id.play_button);
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!isPlaying) {
isPlaying = true;
// Get input strings from the edit texts
String input1 = editText1.getText().toString();
String input2 = editText2.getText().toString();
String speedStr = speedInput.getText().toString();
int speed = TextUtils.isEmpty(speedStr)? 500 : Integer.parseInt(speedStr);
// Separate inputs into arrays of characters
char[] inputChars1 = input1.toCharArray();
char[] inputChars2 = input2.toCharArray();
// Determine the maximum number of iterations needed for both inputs
int maxLength = Math.max(inputChars1.length, inputChars2.length);
// Run the playback in a separate thread
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < maxLength; i++) {
// If we still have characters left in input1, play the corresponding beep tone
if (i < inputChars1.length) {
char c = inputChars1[i];
ToneInfo toneInfo = getToneType(c, i + 1 < inputChars1.length? inputChars1[i + 1] : '\0');
if (toneInfo.frequency != 0) {
playTone(toneInfo.frequency, toneInfo.duration);
if (toneInfo.frequency != 0 && i + 1 < inputChars1.length && (inputChars1[i + 1] == '+' || inputChars1[i + 1] == '-')) {
i++; // 跳过高音或低音标识
}
}
}
// If we still have characters left in input2, play the corresponding beep tone
if (i < inputChars2.length) {
char c = inputChars2[i];
ToneInfo toneInfo = getToneType(c, i + 1 < inputChars2.length? inputChars2[i + 1] : '\0');
if (toneInfo.frequency != 0) {
playTone(toneInfo.frequency, toneInfo.duration);
if (toneInfo.frequency != 0 && i + 1 < inputChars2.length && (inputChars2[i + 1] == '+' || inputChars2[i + 1] == '-')) {
i++; // 跳过高音或低音标识
}
}
}
// Wait for the specified speed between each tone sequence
try {
Thread.sleep(speed);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Signal that the playback has finished
isPlaying = false;
// Update the UI on the main thread
runOnUiThread(new Runnable() {
@Override
public void run() {
playButton.setText("Play");
}
});
}
}).start();
// Update the UI to show that playback is in progress
playButton.setText("Stop");
} else {
// Stop the playback
isPlaying = false;
playButton.setText("Play");
}
}
});
}
private void playTone(int frequency, int duration) {
int sampleRate = 44100;
int numSamples = duration * sampleRate / 1000;
double[] sample = new double[numSamples];
byte[] generatedSnd = new byte[2 * numSamples];
for (int i = 0; i < numSamples; ++i) {
sample[i] = Math.sin(2 * Math.PI * i / (sampleRate / frequency));
}
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
int idx = 0;
for (final double dVal : sample) {
// scale to maximum amplitude
final short val = (short) ((dVal * 32767));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
AudioFormat audioFormat = new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(sampleRate)
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build();
AudioTrack audioTrack = new AudioTrack(audioAttributes, audioFormat,
generatedSnd.length, AudioTrack.MODE_STATIC, 0);
audioTrack.write(generatedSnd, 0, generatedSnd.length);
audioTrack.play();
// 等待音频播放完成
while (audioTrack.getPlaybackHeadPosition() < numSamples) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 释放 AudioTrack 资源
audioTrack.stop();
audioTrack.release();
}
/**
* Map the given character to the corresponding beep tone type
* @param c the character to map
* @param modifier 高音或低音标识
* @return the beep tone type, or -1 if the character is invalid
*/
private ToneInfo getToneType(char c, char modifier) {
int baseFrequency = 0;
int duration = 300;
switch (c) {
case '1':
baseFrequency = 261;
break;
case '2':
baseFrequency = 293;
break;
case '3':
baseFrequency = 329;
break;
case '4':
baseFrequency = 349;
break;
case '5':
baseFrequency = 392;
break;
case '6':
baseFrequency = 440;
break;
case '7':
baseFrequency = 493;
break;
case '-':
baseFrequency = 0;
break;
default:
baseFrequency = 0;
duration = 0;
break;
}
if (modifier == '*') {
baseFrequency *= 2; // 高音,频率翻倍
} else if (modifier == '.') {
baseFrequency /= 2; // 低音,频率减半
}
return new ToneInfo(baseFrequency, duration);
}
}
05-12
129
