代码之家  ›  专栏  ›  技术社区  ›  Jeremy Logan

用Android玩任意音

  •  83
  • Jeremy Logan  · 技术社区  · 16 年前

    有没有办法让Android发出任意频率的声音(也就是说,我不想预先录制声音文件)?

    我环顾四周 ToneGenerator

    有什么想法吗?

    10 回复  |  直到 16 年前
        1
  •  113
  •   Steve Pomeroy    11 年前

    我最初发现 this example code 在博客上,但它有一些错误,产生了一些可怕的声音。我已经修复了bug,并在这里发布了生成的代码。似乎对我很有效!

    public class PlaySound extends Activity {
        // originally from http://marblemice.blogspot.com/2010/04/generate-and-play-tone-in-android.html
        // and modified by Steve Pomeroy <steve@staticfree.info>
        private final int duration = 3; // seconds
        private final int sampleRate = 8000;
        private final int numSamples = duration * sampleRate;
        private final double sample[] = new double[numSamples];
        private final double freqOfTone = 440; // hz
    
        private final byte generatedSnd[] = new byte[2 * numSamples];
    
        Handler handler = new Handler();
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.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() {
                    genTone();
                    handler.post(new Runnable() {
    
                        public void run() {
                            playSound();
                        }
                    });
                }
            });
            thread.start();
        }
    
        void genTone(){
            // fill out the array
            for (int i = 0; i < numSamples; ++i) {
                sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/freqOfTone));
            }
    
            // 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);
    
            }
        }
    
        void playSound(){
            final AudioTrack 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);
            audioTrack.play();
        }
    }
    
        2
  •  28
  •   JHobern Jim Michaels    7 年前

    增加振幅上升和下降以避免咔哒声。

    添加代码以确定大头针何时完成播放。

    double duration = 1;            // seconds
    double freqOfTone = 1000;       // hz
    int sampleRate = 8000;          // a number
    
    double dnumSamples = 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(freqOfTone * 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 = 0 ;
    
    int ramp = numSamples / 20 ;                                     // Amplitude ramp as a percent of sample count
    
    
    for (i = 0; i< ramp; ++i) {                                      // Ramp amplitude up (to avoid clicks)
        double dVal = sample[i];
                                                                     // Ramp up to maximum
        final short val = (short) ((dVal * 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 = i; i< numSamples - ramp; ++i) {                         // Max amplitude for most of the samples
        double dVal = sample[i];
                                                                     // 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);
    }
    
    for (i = i; i< numSamples; ++i) {                                // Ramp amplitude down
        double dVal = sample[i];
                                                                     // Ramp down to zero
        final short val = (short) ((dVal * 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);
    }
    
    AudioTrack audioTrack = null;                                    // Get audio track
    try {
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
            sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT, (int)numSamples*2,
            AudioTrack.MODE_STATIC);
        audioTrack.write(generatedSnd, 0, generatedSnd.length);        // Load the track
        audioTrack.play();                                             // Play the track
    }
    catch (Exception e){
        RunTimeError("Error: " + e);
        return false;
    }
    
    int x =0;
    do{                                                              // Monitor playback to find when done
        if (audioTrack != null) 
            x = audioTrack.getPlaybackHeadPosition(); 
        else 
            x = numSamples;
    } while (x<numSamples);
    
    if (audioTrack != null) audioTrack.release();                    // Track play done. Release track.
    
        3
  •  8
  •   meese    8 年前

    我把上面这些美妙的解决方案包装成一个整洁的小包装,作为一个简单的可配置蜂鸣器,它更容易使用。它在后台线程中运行,并且有停止和播放方法以及一些可以设置的选项。

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

    你用它来做连续的蜂鸣器

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

    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

        4
  •  4
  •   extreme    12 年前

    由于在一些旧的android版本中存在一个bug,在使用MODE\u STATIC时会导致内存泄漏,所以我修改了Xarph上面的回答,使用MODE\u STREAM。希望它能帮助一些人。

    public void playTone(double freqOfTone, double duration) {
     //double duration = 1000;                // seconds
     //   double freqOfTone = 1000;           // hz
        int sampleRate = 8000;              // a number
    
        double dnumSamples = 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(freqOfTone * 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 = 0 ;
    
        int ramp = numSamples / 20 ;                                    // Amplitude ramp as a percent of sample count
    
    
        for (i = 0; i< ramp; ++i) {                                     // Ramp amplitude up (to avoid clicks)
            double dVal = sample[i];
                                                                        // Ramp up to maximum
            final short val = (short) ((dVal * 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 = i; i< numSamples - ramp; ++i) {                        // Max amplitude for most of the samples
            double dVal = sample[i];
                                                                        // 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);
        }
    
        for (i = i; i< numSamples; ++i) {                               // Ramp amplitude down
            double dVal = sample[i];
                                                                        // Ramp down to zero
            final short val = (short) ((dVal * 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);
        }
    
        AudioTrack audioTrack = null;                                   // Get audio track
        try {
             int bufferSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                    sampleRate, AudioFormat.CHANNEL_OUT_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, bufferSize,
                    AudioTrack.MODE_STREAM);
            audioTrack.play();                                          // Play the track
            audioTrack.write(generatedSnd, 0, generatedSnd.length);     // Load the track
        }
        catch (Exception e){
        }
        if (audioTrack != null) audioTrack.release();           // Track play done. Release track.
    }
    
        5
  •  3
  •   simou    12 年前

    下面是另一个演示简单synth和一些UI的博客

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

    您可能还对csound或用于android的pdlib(纯数据库)感兴趣。

        6
  •  3
  •   Jeff Bootsholz    11 年前

    public class MainActivity extends Activity {
        private final int duration = 30; // seconds
        private final int sampleRate = 8000;
        private final int numSamples = duration * sampleRate;
        private final double sample[] = new double[numSamples];
        private final double freqOfTone = 440; // hz
        private final byte generatedSnd[] = new byte[2 * numSamples];
        Handler handler = new Handler();
        private AudioTrack audioTrack;
        private boolean play = false;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                    8000, AudioFormat.CHANNEL_OUT_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, numSamples,
                    AudioTrack.MODE_STREAM);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
    
            // Use a new tread as this can take a while
            Thread thread = new Thread(new Runnable() {
                public void run() {
    
                    handler.post(new Runnable() {
    
                        public void run() {
                            playSound();
                            genTone();
                        }
                    });
                }   
            });
            thread.start();
        }
    
        void genTone(){
            // fill out the array
            while(play){
                    for (int i = 0; i < numSamples; ++i) {
                    //  float angular_frequency = 
                        sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/freqOfTone));
                    }
                    int idx = 0;
    
                    // convert to 16 bit pcm sound array
                    // assumes the sample buffer is normalised.
                    for (double dVal : sample) {
                        short val = (short) (dVal * 32767);
                        generatedSnd[idx++] = (byte) (val & 0x00ff);
                        generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
                    }
                    audioTrack.write(generatedSnd, 0, numSamples);
                }
            }
    
    
        void playSound(){
            play = true;
            audioTrack.play();
        }
    }
    
        7
  •  2
  •   Singhak    12 年前
        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);
        } 
    

    //你可以在synth\u频率中添加任意值来获得变化的声音例如,你可以添加随机变量来获得声音

        8
  •  2
  •   Vahe Gharibyan    9 年前

    主修(16注)

     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();
      }
    
    }
    
        9
  •  2
  •   shinta    9 年前

    https://github.com/karlotoy/perfectTune

    它很容易使用

    将此添加到依赖项

     compile 'com.github.karlotoy:perfectTune:1.0.2'
    

    你是这样用的:

    PerfectTune perfectTune = new PerfectTune();
    perfectTune.setTuneFreq(desire_freq);
    perfectTune.playTune();
    

    要停止调音:

    perfectTune.stopTune();
    
        10
  •  1
  •   endolith    16 年前
    推荐文章