Android Drum machine

For iOS (iPhone, iPad & iPod), Android, Windows Phone, etc. App and Hardware talk
RELATED
PRODUCTS

Post

Can you please share the wav file you're playing?

Post

https://www.dropbox.com/s/tue93finb42k9ib/sinc5.wav

Its a sine at c5, its playing c4 in my test app.

EDIT: Just to be sure, I call getSampleRate on my AudioTrack once it is initialized, and it return 44100.

EDIT: I just realized I had the sample as a stereo file which explains why in mono it is playing at half the frequency. SO that problem is solved. But there still remains the tempo problem.

Now that the sample problem is sorted out it confirms that the sample is being read and played correctly. The sample is a sine at c5, and audio track is playing back a sine c5 with no pitch or timbre change, or distortion whatsoever.

Post

Ap0C552 wrote: EDIT: I just realized I had the sample as a stereo file which explains why in mono it is playing at half the frequency. SO that problem is solved. But there still remains the tempo problem.

Now that the sample problem is sorted out it confirms that the sample is being read and played correctly. The sample is a sine at c5, and audio track is playing back a sine c5 with no pitch or timbre change, or distortion whatsoever.
Bingo! That's what I suspected, therefore I wanted the file.
Great that you sorted it out ;)

When you read a 2-channel (stereo), 16bit wav, the byte stream is as followed:

Code: Select all

00000000 11111111 00000000 11111111
<------> <------> <------> <------>
 lowCh1   higCh1   lowCh2   higCh2
This is what is called a frame. And yes, when you play a 4 byte frame on an Mono AudioTrack (which expects a 2 byte frame) it's played at half speed and timbre.

This resource explains very well how multi channel files are organized. It also points to the bastardized wave formats and header types.
http://home.roadrunner.com/~jgglatt/tech/wave.htm

SO that problem is solved. But there still remains the tempo problem.
I would say, since you're handling your sample as bytes (that's what you do, right?), and you count every byte in your sequencer to calculate the time, then you count 4 bytes for each sample, which finally results in a 4 times faster sequencer speed.

Count the frames instead, and the tempo will be fine.

Post

Yes that is the tempo problem!!! How did this elude me! :s

I am doing my calculation as

long bufferTime=(1000000000/44100)*buffSize;

where buffSize is the size in bytes, when it should be buffSize/2 aka the size in short.

Finally I can get back to experimenting with the sequencer!!

I am just wondering though. How do you write new triggers to play into the sequencer when it is playing at realtime. Since with this approach you are writting lots of data ahead of time to the audiotrack.

Post

Ap0C552 wrote: where buffSize is the size in bytes, when it should be buffSize/2 aka the size in short.
Actually it's bufferSize/4, keep in mind that you're playing a stereo file, which means 2 bytes for each channel.
Ap0C552 wrote:Finally I can get back to experimenting with the sequencer!!
I am just wondering though. How do you write new triggers to play into the sequencer when it is playing at realtime. Since with this approach you are writting lots of data ahead of time to the audiotrack.
Just keep in mind, that always the audio process (an independent thread) is the master of almost everything. The audio loop has to ask the sequencer if there's something to play, never the opposite way.

The sequencer is just the orchestrator, the keeper of the plan whatever has to be played at a specific time. That plan can be changed all the time, by someone tapping the screen, by a sequence loader, by a song arranger, whatever. It can be changed by any thread in the system (the gui thread, some loader threads, also by the audio thread).

So good luck then;)

Post

I understand that.

But...

My audio loop is writing as fast as it can to the AudioTrack. And loading its buffer with lots data.

Now if I change something in the sequencer, the audiotrack buffer has already been loaded with lots of data to play. So the loop that writes to the audio track can start writing something different according to sequencer changes, but the audiotrack might have a a large buffer full of data to play before that change is realized.

Post

You have to mix all playing sample buffers together (from every playing sample) to a single buffer before you write it to the audioTrack. E.g. when you have 6 samplers, loop over your samplers, for each get its buffer and push it to some mixer. When you're through take the final mixdown and write it to the audioTrack. To be able to do this you need to have short[] or float[] buffers instead of byte buffers, only the final mixdown has to be converted back into bytes before the write.

Post

That was not really what I was getting at.

Forget about multiple samples for this example.

What I am worried about is changes is sequencer data being recognized in the playback in realtime.

My loop for generating the output buffer is writing to the audiotrack at no set maximum speed. Correct? It is writing as fast as it can to audio track. Now in a period of some time, lets say 1 second, it could have wrote 15 seconds of audio to the audiotrack. So there is 15 seconds of audio buffered in audio track.

Now if I make a change to sequencer data, that change will immediately be recognized in my output loop that is writing to audiotrack. But that change in sequencer data will not be recognized in the audio being play for a long time, since my output loop has filled the audiotrack buffer up with a lot of audio waiting to be played correct?

So by writing internal buffer with no limit to speed, its like I build up a gigantic input latency in my sequencer.

Post

Ap0C552 wrote:But that change in sequencer data will not be recognized in the audio being play for a long time, since my output loop has filled the audiotrack buffer up with a lot of audio waiting to be played correct?
No, AudioTrack just buffers its own bufferSize, and if your audioSystem is faster than that, the AudioTrack just lets your process wait. So don't worry about that, if your audioProcess asks the sequencer for "events" (something to do), then it'll be executed within the latency time (the audioTrack's buffer size).

Usually it's more the other way... that your audio process is not fast enough to serve the audioTrack with enough data ;), then you get dropouts.

Post

Ok I see. When I tested this I had some bugs, but now my test are working for realtime sequencer changes.

I think a sequencer with crisp timing will be a reality for me now!

My first born will be named Planeth

Post

Ap0C552 wrote:Ok I see. When I tested this I had some bugs, but now my test are working for realtime sequencer changes.

I think a sequencer with crisp timing will be a reality for me now!
Great, so good luck with it. Looking forward to see the finished app.
Ap0C552 wrote:My first born will be named Planeth
yeah :D

Post

Just wondering. You were talking about converting and convert back. AudioTrack has write short method. Can I not just keep in short then?

Post

Ap0C552 wrote:Just wondering. You were talking about converting and convert back. AudioTrack has write short method. Can I not just keep in short then?
Cannot answer that for sure, but it may be. Unfortunately this is not clearly described in the api docs. I would just try. If it is actually what it looks like, a write method for 16bit short samples, it could have a better performance as the byte method, because the short samples will be splitted into bytes at the native layer.

Internally, the audiotrack does that:

Code: Select all

native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
So anyway, please let me know once you found out, would be interesting for me as well.

Post

Its works fine. So I will stick with that method. :)

Post

Why are you guys (android) torturing yourselves..?!
Buy an iPad and be happy if you want to create music that is...
Android OS is not optimIsed for music production I'm afraid :(

Post Reply

Return to “Mobile Apps and Hardware”