3

I'm trying to understand the AudioTrack class in Android, and I want to learn how to properly modulate the sound wave I'm generating.

I'm using an async task class to run the wave in the background of the UI and I'm able to generate sound. I can also easily change frequency, but when I do so dynamically the pitch shifts from one to another abruptly and not gradually as I was hoping. There is also the question of simulating some basic functions of a synth. I have tried to create an lfo loop to modulate the wave but I'm not sure if this is the best way to approach it, so basically there are three questions when it comes to this:

1): Is there any way to be able to choose between the two types of pitch shift, gradual/step.

2): Am I implementing the LFO correctly?

3): If I want to have textured sounds do I have to run different tracks? (eg: High and low freq) Or should I do it all in this one 'doInBackground' method, Should I create one class for each? My thought was originally to create a sine wave and process it accordingly to create the sound(s) I need, Basically I'm not sure how to approach adding textures to the sound wave in terms of threading and signal processing.

Some context: What I'm trying to accomplish is to build an app that with user input generates harmonics at intervals, kind of like a dynamic sequencer.

How do I organize and build the wave filters needed to process that?

Sorry, I know it's a lot but It's incredibly fascinating to me and any help in the right direction is immensely appreciated.

Here's my code: It currently generates a stream of sound but with some audible artifacts.

 private class AudioSynthesisTask extends AsyncTask<Void, Void, Void> {
    @Override
    protected Void doInBackground(Void... params) {
        final int SAMPLE_RATE = 44100;
        int minSize = AudioTrack.getMinBufferSize( //Sample size. Individual sample.
                SAMPLE_RATE,                    // Numerical cycles per second
                AudioFormat.CHANNEL_OUT_MONO,   // Channel to output
                AudioFormat.ENCODING_PCM_16BIT  // pulse code modulation giving you
                // encoding at 16 bits per cycle to define a sample rate.
        );
        AudioTrack audioTrack = new AudioTrack( //connects the calculation to the hardware
                AudioManager.STREAM_MUSIC,
                SAMPLE_RATE,
                AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT,
                minSize,
                AudioTrack.MODE_STREAM);
        audioTrack.play();
        AudioTrack audioTrack2 = new AudioTrack( //connects the calculation to the hardware
                AudioManager.STREAM_MUSIC,
                SAMPLE_RATE,
                AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT,
                minSize,
                AudioTrack.MODE_STREAM);
        audioTrack2.play();

        short[] sample_buffer = new short[minSize]; //will be fed as a string.
        float angle = 0;
        while (true) {
            if (play) {//On touch
                for (int j = 0; j < sample_buffer.length; j++) {
                    float frequency = (float) ((2 * Math.PI) * low_frequency_oscillator / SAMPLE_RATE); 
                    angle += frequency;

                    sample_buffer[j] = (short) (low_frequency_oscillator * 2 * (-0.02 / 1200 + 0.5 * angle));
                    sample_buffer[j] = (short) (amplitude * Math.cos(angle)); 
                }
                audioTrack.write(sample_buffer, 0, sample_buffer.length);
            }

            if (play) {
                for (int i = 0; i < sample_buffer.length; i++) {
                    float angular_frequency = (float) (2 * Math.PI) * synth_frequency / SAMPLE_RATE;
                    angle += angular_frequency;
                    sample_buffer[i] = (short) (amplitude * ((float) Math.cos(angle)));
                }
                audioTrack2.write(sample_buffer, 0, sample_buffer.length);//test track
            }
        }
    }
}

So I read this and I'm wondering if it applies to what I'm trying to do: AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and FutureTask. (Straight from the doc) from: How to execute other threads from doinbackground()

Community
  • 1
  • 1
Lighterletter
  • 209
  • 2
  • 13

0 Answers0