অ্যান্ড্রয়েডের সাথে একটি স্বেচ্ছাসেবী সুর বাজানো


93

অ্যান্ড্রয়েডকে নির্বিচারে ফ্রিকোয়েন্সি শোনার কোনও উপায় আছে (অর্থাত্ আমি প্রাক-রেকর্ডকৃত সাউন্ড ফাইল রাখতে চাই না)?

আমি চারপাশে দেখেছি এবং টোনজেনেটর একমাত্র জিনিস যা আমি এটির নিকটবর্তী ছিল তা খুঁজে পেতে সক্ষম হয়েছি, তবে এটি কেবলমাত্র স্ট্যান্ডার্ড ডিটিএমএফ টোনগুলি আউটপুট দিতে সক্ষম বলে মনে হচ্ছে।

কোন ধারনা?


4
আপনি কি কোনও বাস্তব সমাধান খুঁজে পেয়েছেন?
o0 '

21
না, তবে আমি প্রকল্পটি না করে শেষ করেছি।
জেরেমি লোগান

4
@ জেরেমি লোগান এবং আপনি ইতিবাচক নেতিবাচক প্রতিক্রিয়া পেয়েছেন। হাঃ হাঃ হাঃ.
TheRealChx101

উত্তর:


111

আমি মূলত একটি ব্লগে এই উদাহরণ কোডটি পেয়েছি , তবে এতে কিছু বাগ রয়েছে যা কিছু ভয়াবহ শব্দ উত্পন্ন করেছিল। আমি বাগগুলি স্থির করেছি এবং ফলাফল কোড এখানে পোস্ট করেছি। আমার জন্য ভাল কাজ মনে হচ্ছে!

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

4
এই লাইন সঠিক? অডিওট্র্যাক.উইরাইট (জেনারেটসেন্ড, 0, নামসাম্পলস); বা এটি নমুনা * 2 হওয়া উচিত কারণ প্রতি স্যাম্পলটিতে 2 বাইট রয়েছে। এছাড়াও লেখার পদ্ধতিতেও শর্টসের একটি অ্যারে লাগে তাই বাইটগুলির মধ্যস্থতাকারী অ্যারে তৈরি করার সুবিধা কী?
ড্যামিয়ান কেনেডি

4
এটি প্রকৃতপক্ষে একটি দুর্দান্ত উদাহরণ, অনেক অনেক ধন্যবাদ। তবে আমি খুঁজে পেয়েছি আরেকটি বাজে বাগ (যদি আপনি কোডটি প্রসারিত করেন), যা হ'ল: অডিওট্র্যাক.উরাইট (উত্পন্নস্রেন্ড, 0, নামসামেলস) অডিওট্র্যাক.উইরাইট (জেনারেটস্যান্ড, 0, 2 * নাম্বার) হওয়া উচিত বা আরও ভাল অডিও ট্র্যাক.রাইট (জেনারেটস্যান্ড, 0) , জেনারেটসেন্ড.লেন্থ);
অডিওড্রয়েড

6
অডিওট্র্যাক কনস্ট্রাক্টরে "নামসাম্পলস" ব্যবহার করার পরিবর্তে আপনার জেনার্সডেন্ডেলথ ব্যবহার করা উচিত কারণ পঞ্চম প্যারামিটারটি "বাইটে বাফার সাইজ"। উদাহরণটি কেবল স্বরটির প্রথমার্ধটি খেলে।
টর্বেন

5
@ ব্ল্যাক 27 নমুনাগুলি ভাসমান পয়েন্টগুলিতে প্রশস্ততা পরিসীমা পর্যন্ত তৈরি করা 0.0হয়েছে 1.0। এর দ্বারা গুণ 32767করলে এটি 16-বিট নির্দিষ্ট পয়েন্ট রেঞ্জে রূপান্তরিত হয়। Audiotrack বাফার সামান্য হতে আশা endian বিন্যাস। সুতরাং পরবর্তী দুটি লাইন কেবল বড় এন্ডিয়ান থেকে বাইট ক্রমটিকে সামান্য এন্ডিয়ানে রূপান্তর করে।
ains

4
প্রাইভেট স্ট্যাটিক ফাইনাল ইন স্যাম্পলরেট ব্যবহার করে = 192000; আমি আল্ট্রা-
সোনিক

26

উপরের কোডটি উন্নত করা হচ্ছে:

ক্লিকগুলি এড়ানোর জন্য প্রশস্ততা র‌্যাম্প আপ যোগ করুন এবং র‌্যাম্প ডাউন করুন।

কবে খেলা শেষ হয়েছে তা নির্ধারণের জন্য কোড যুক্ত করুন।

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.

4
প্রাথমিক পরিবর্তনটি প্রশস্ততার উপরে এবং নিচে র‌্যাম্প ছিল। মূল কোডটি শুরু হয়েছে এবং সর্বাধিক প্রশস্ততার সাথে শেষ হয়েছে। এটি স্বরটির শুরু এবং শেষে ক্লিকগুলি তৈরি করে। এই কোডটি প্রশস্ততার পরিমাণকে 0 থেকে সম্পূর্ণ প্রশস্ততার উপরে প্রথম 20% নমুনার উপরে ফেলেছে। এটি পরে সম্পূর্ণ প্রশস্ততা থেকে শূন্যে নেমে আসে 20% নমুনাগুলির উপরে। টোনগুলি মসৃণ এবং আরও অনেক মনোরম। অন্য পরিবর্তনটি হ'ল সুরটি বাজানো নিরীক্ষণ করা এবং টোন বাজানো শেষ না হওয়া পর্যন্ত চালিয়ে যাওয়া না।
Xarph

আমি এটি চালাতে চাই না..আমি প্রথম চালাতে সক্ষম হয়েছি ... তবে আপনি কী করেছেন তা কীভাবে এটি পরিবর্তন করতে হবে তা সত্যিই বুঝতে পারছি না ... ক্লিকের শব্দ থেকে মুক্তি পাওয়ার জন্য এটি সত্যিই সহায়ক হবে। ।
কোডার

4
+1, তবে এই উত্তরের কোডটি সংকলনের নিকটে আসে না। আমি এটি এখানে সঠিকভাবে প্রয়োগ করেছি: gist.github.com/SuspendPhan/7596139 স্টিভের জেনটোন () পদ্ধতিটি আমার সাথে প্রতিস্থাপন করুন এবং আপনি র‌্যাম্পিংয়ের প্রভাব পাবেন।
ডিলান পি

যেহেতু MODE_STATIC এ একটি মেমরি ফাঁস রয়েছে, তাই আমি নীচে MODE_STREAM ব্যবহার করার জন্য কোডটি সংশোধন করেছি
চূড়ান্ত

এপিআই দিয়ে শুরু করে সেটভলিউম () ব্যবহার করে র‌্যাম্প করা সম্ভব। এটি কেবলমাত্র একটি খুব সামান্য নমুনা লুপিং এবং এমনকি গতিশীল দৈর্ঘ্যের জন্য একটি শব্দ বাজানো সক্ষম করে (উদাহরণস্বরূপ যখন ব্যবহারকারী একটি বোতাম ধারণ করে)। কোড উদাহরণ: github.com/stefanhaustein/android-tone-generator/blob/master/…
স্টেফান হস্টেইন

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

এটি সম্পর্কে এখানে গিটহাব এখানে প্রসারিত ব্লগ পোস্ট


@ মেলচেস্টার এটি এখন ঠিক আছে।
শীর্ষস্থানীয়দের

4

যেহেতু কিছু পুরানো অ্যান্ড্রয়েড সংস্করণগুলিতে একটি বাগ রয়েছে যা MODE_STATIC ব্যবহার করার সময় মেমরি ফাঁস হওয়ার কারণ হয়ে থাকে, তাই আমি MODE_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.
}

3

এখানে অন্য ব্লগটি একটি সাধারণ সিন্থ প্লাস কিছু ইউআই ডেমো করছে

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

আপনি অ্যান্ড্রয়েডের জন্য সাসাউন্ড বা পিডিলিব (খাঁটি ডেটা লিব) সম্পর্কে আগ্রহী হতে পারেন।


3

সিংহাকসের উত্তরের ভিত্তিতে সংশোধিত কোড

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

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

// পরিবর্তনের শব্দ পেতে আপনি সিন্থ_ফ্রিকোয়েন্সিতে নির্বিচার মান যোগ করতে পারেন উদাহরণস্বরূপ আপনি শব্দ পেতে র্যান্ডম ভেরিয়েবল যুক্ত করতে পারেন


আপনি এগুলিকে শেষে একটি সংক্ষিপ্ত রূপে রূপান্তর করছেন। ভাসা হিসাবে কোণ করার কোনও কারণ নেই। ডাবল ম্যাথ একই গতি এবং কাস্টিং একগুচ্ছ প্রয়োজন হয় না।
তাতারাইজ করুন

2

বড় করুন (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();
  }

}

2

এই সহায়ক লাইব্রেরি দেখুন

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.