如何在安卓设备中生成准确的频率

3
生成Android中所需的频率,我知道两种方法,每种方法都有自己的问题。
第一种方法是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);

这段话的意思是:“这只增加了一个精度,但解决了幅度问题,但需要安卓5,效率低下,而且1个精度对于非常低的音符(如第二个钢琴八度)不够。是否有可能制作更精确的频率?还有其他方法吗?”

这里的 frequency 的值是多少? - Faizan Mubasher
1个回答

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();
  }

嗨,我想将持续时间设置为低于0.06,但我的生成物无法工作,并且没有任何声音。你知道原因吗? - Mohamad Hafezi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接