Playing an arbitrary tone with Android

后端 未结 10 2092
伪装坚强ぢ
伪装坚强ぢ 2020-11-22 10:38

Is there any way to make Android emit a sound of arbitrary frequency (meaning, I don\'t want to have pre-recorded sound files)?

I\'ve looked around and ToneGenerator

相关标签:
10条回答
  • 2020-11-22 11:02
        float synth_frequency = 440;
        int minSize = AudioTrack.getMinBufferSize(SAMPLE_RATE,
    AudioFormat.CHANNEL_OUT_MONO,
    AudioFormat.ENCODING_PCM_16BIT);
    AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
    SAMPLE_RATE,
    AudioFormat.CHANNEL_OUT_MONO,
    AudioFormat.ENCODING_PCM_16BIT,
    minSize,
    AudioTrack.MODE_STREAM);
    audioTrack.play();
    short[] buffer = new short[minSize];
    float angle = 0;
    while (true) 
    {
        if (play)
        {
            for (int i = 0; i < buffer.length; i++)
            {
                float angular_frequency =
                (float)(2*Math.PI) * synth_frequency / SAMPLE_RATE;
                buffer[i] = (short)(Short.MAX_VALUE * ((float) Math.sin(angle)));
                angle += angular_frequency;
        }
            audioTrack.write(buffer, 0, buffer.length);
        } 
    

    // You can add arbitrary value in synth_frequency to get change sound for example you can add random variable to get sound

    0 讨论(0)
  • 2020-11-22 11:04

    Do major (16 notes)

     public class MainActivity extends AppCompatActivity {
    
      private double mInterval = 0.125;
      private int mSampleRate = 8000;
      private byte[] generatedSnd;
    
      private final double mStandardFreq = 440;
    
      Handler handler = new Handler();
      private AudioTrack audioTrack;
    
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      }
    
      @Override
      protected void onResume() {
        super.onResume();
    
        // Use a new tread as this can take a while
        final Thread thread = new Thread(new Runnable() {
            public void run() {
    
                byte[] tempByte = new byte[0];
                for (int i = 0; i < 16 ; i++ ){
                    double note = getNoteFrequencies(i);
                    byte[] tonByteNote = getTone(mInterval, mSampleRate, note);
                    tempByte = concat(tonByteNote, tempByte);
                }
                generatedSnd = tempByte;
    
                handler.post(new Runnable() {
                    public void run() {
                        playTrack(generatedSnd);
                    }
                });
            }
        });
        thread.start();
      }
    
      public byte[] concat(byte[] a, byte[] b) {
        int aLen = a.length;
        int bLen = b.length;
        byte[] c= new byte[aLen+bLen];
        System.arraycopy(a, 0, c, 0, aLen);
        System.arraycopy(b, 0, c, aLen, bLen);
        return c;
      }
    
      private double getNoteFrequencies(int index){
        return mStandardFreq * Math.pow(2, (double) index/12.0d);
      }
    
      private byte[] getTone(double duration, int rate, double frequencies){
    
        int maxLength = (int)(duration * rate);
        byte generatedTone[] = new byte[2 * maxLength];
    
        double[] sample = new double[maxLength];
        int idx = 0;
    
        for (int x = 0; x < maxLength; x++){
            sample[x] = sine(x, frequencies / rate);
        }
    
    
        for (final double dVal : sample) {
    
            final short val = (short) ((dVal * 32767));
    
            // in 16 bit wav PCM, first byte is the low order byte
            generatedTone[idx++] = (byte) (val & 0x00ff);
            generatedTone[idx++] = (byte) ((val & 0xff00) >>> 8);
    
        }
    
        return generatedTone;
    }
    
      private AudioTrack getAudioTrack(int length){
    
        if (audioTrack == null)
            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                    mSampleRate, AudioFormat.CHANNEL_OUT_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, length,
                    AudioTrack.MODE_STATIC);
    
        return audioTrack;
      }
    
      private double sine(int x, double frequencies){
        return Math.sin(  2*Math.PI * x * frequencies);
      }
    
      void playTrack(byte[] generatedSnd){
        getAudioTrack(generatedSnd.length)
                .write(generatedSnd, 0, generatedSnd.length);
        audioTrack.play();
      }
    
    }
    
    0 讨论(0)
  • 2020-11-22 11:05

    I wrapped the above wonderful solutions into a neat little package that's more useable out of the box as a simple configurable buzzer. It runs it in a background thread and has stop and play methods and a handful of options you can set.

    It's up on JCenter so you can add it to your dependencies list like this

    compile 'net.mabboud:android-tone-player:0.2'
    

    and you use it like this for a continuous buzzer

    ContinuousBuzzer tonePlayer = new ContinuousBuzzer();
    tonePlayer.play();
    
    // just an example don't actually use Thread.sleep in your app
    Thread.sleep(1000); 
    tonePlayer.stop();
    

    or a buzzer played only once and you can set frequency and volume like this

    OneTimeBuzzer buzzer = new OneTimeBuzzer();
    buzzer.setDuration(5);
    
    // volume values are from 0-100
    buzzer.setVolume(50);
    buzzer.setToneFreqInHz(110);
    

    Extended blog post here about it here GitHub here

    0 讨论(0)
  • 2020-11-22 11:06

    Here's another blog demoing a simple synth plus some UI

    http://audioprograming.wordpress.com/2012/10/18/a-simple-synth-in-android-step-by-step-guide-using-the-java-sdk/

    You might also be interested in csound or pdlib (pure data lib) for android.

    0 讨论(0)
提交回复
热议问题