为了在android中按数字生成所需的频率,我知道2种方式,每种方式都有自己的大问题。
第一种方式是PCM_16_bit:
frequency = (int) frequency;
final int numberOfSamples = duration * sampleRate;
final byte[] generatedSnd = new byte[numberOfSamples * 2];
double dVal;
int idx = 0;
for (int i = 0; i < numberOfSamples; ++i) {
dVal = Math.sin(2 * Math.PI * i / (sampleRate / frequency));
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
// scale to maximum amplitude
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);
}
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
AudioTrack.MODE_STATIC);
audioTrack.write(generatedSnd, 0, generatedSnd.length);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
loudnessEnhancer = new LoudnessEnhancer(audioTrack.getAudioSessionId());
loudnessEnhancer.setTargetGain(maxFrequency - (int) frequency);
}
仅适用于短值,因此没有精确数和有限幅度,因此需要具有Android 4.4依赖性的LoudnessEnhancer,这会增加收益并降低质量。
第二种方式是:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
final int numberOfSamples = duration * sampleRate * 4;
final float[] generatedSnd = new float[numberOfSamples];
float amplitude = 2;//Increase in amplitude has a relation with increase in noise.
for (int i = 0; i < numberOfSamples; ++i)
generatedSnd[i] = (float) (Math.sin((2 * Math.PI * i * frequency) / sampleRate)) * amplitude;
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_FLOAT, generatedSnd.length,
AudioTrack.MODE_STATIC);
audioTrack.write(generatedSnd, 0, generatedSnd.length, AudioTrack.WRITE_BLOCKING);
这只增加了一个精度但是为我解决了振幅问题,但是它需要android 5效率低,而且1精度不足以用于非常低的音符,如第二钢琴八度音阶。
是否可以制作更精确的频率? 有另一种方式吗?
答案 0 :(得分:0)
尝试一下,我认为还可以:
isPlaying = true;
int sampleRate = 44100;// 44.1 KHz
double dnumSamples = (double) duration * sampleRate;
dnumSamples = Math.ceil(dnumSamples);
int numSamples = (int) dnumSamples;
double[] sample = new double[numSamples];
byte[] generatedSnd = new byte[2 * numSamples];
for (int i = 0; i < numSamples; ++i) { // Fill the sample array
sample[i] = Math.sin(freq * 2 * Math.PI * i / (sampleRate));
}
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalized.
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
int idx = 0;
int i;
int ramp = numSamples / 20; // Amplitude ramp as a percent of sample count
for (i = 0; i < ramp; ++i) { // Ramp amplitude up (to avoid clicks)
// Ramp up to maximum
final short val = (short) (sample[i] * 32767 * i / ramp);
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
for (i = ramp; i < numSamples - ramp;
++i) { // Max amplitude for most of the samples
// scale to maximum amplitude
final short val = (short) (sample[i] * 32767);
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
for (i = numSamples - ramp; i < numSamples; ++i) { // Ramp amplitude down
// Ramp down to zero
final short val = (short) (sample[i] * 32767 * (numSamples - i) / ramp);
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
try {
int bufferSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
audioTrack =
new AudioTrack(AudioManager.STREAM_SYSTEM, sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);
audioTrack.setNotificationMarkerPosition(numSamples);
audioTrack.setPlaybackPositionUpdateListener(
new AudioTrack.OnPlaybackPositionUpdateListener() {
@Override public void onPeriodicNotification(AudioTrack track) {
// nothing to do
}
@Override public void onMarkerReached(AudioTrack track) {
// toneStoppedListener.onToneStopped();
}
});
// Sanity Check for max volume, set after write method to handle issue in android
// v 4.0.3
float maxVolume = AudioTrack.getMaxVolume();
if (volume > maxVolume) {
volume = maxVolume;
} else if (volume < 0) {
volume = 0;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
audioTrack.setVolume(volume);
} else {
audioTrack.setStereoVolume(volume, volume);
}
audioTrack.play(); // Play the track
audioTrack.write(generatedSnd, 0, generatedSnd.length); // Load the track
} catch (Exception e) {
e.printStackTrace();
}