Back to project page android-wav-mixer.
The source code is released under:
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2014 Nathan Sizemore <nathanrsizemore@gmail.com> Everyone is permitted to copy and distribute verbatim or modified ...
If you think the Android project android-wav-mixer listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.nathansizemore.beatmaker.audiomixer; /*w ww .j a v a 2 s . co m*/ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.ArrayList; import java.util.Arrays; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import com.example.beatmaker.R; import com.nathansizemore.beatmaker.audiomixer.extras.MixerStatus; import com.nathansizemore.beatmaker.audiomixer.extras.SampleChange; import com.nathansizemore.beatmaker.audiomixer.extras.WavStream; public class Mixer extends Thread { // Logging support private final String TAG = "Mixer"; // Activity related variables private Context context; public Handler pipeLine; private MixerStatus activityCallback; private PipedOutputStream stream; // Audio stream related variables private ArrayList<AudioChannel> channels; private byte[] wavHeader; private boolean streaming = false; private Clip[] audioClips = { new Clip(R.raw.drums, "drums"), new Clip(R.raw.bass, "bass"), new Clip(R.raw.bass_synth, "bass_synth"), new Clip(R.raw.piano, "piano") }; public Mixer(Activity activity) { channels = new ArrayList<AudioChannel>(); context = activity.getBaseContext(); try { activityCallback = (MixerStatus)activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement MixerStatus"); } } @SuppressLint("HandlerLeak") // Queue will be flushed // Reference will be killed @Override public void run() { loadAudioData(); Looper.prepare(); pipeLine = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case SampleChange.VOLUME: adjustVolume(msg.arg1, msg.arg2); break; case SampleChange.PITCH: adjustPitch(msg.arg1, msg.arg2); break; case SampleChange.TEMPO: adjustTempo(msg.arg1, msg.arg2); break; case SampleChange.SCRATCH: addScratch(msg.obj); break; case SampleChange.ADD_CLIP: addClip(msg.obj); break; case SampleChange.REMOVE_CHANNEL: removeChannel(msg.arg1); break; case SampleChange.SAVE_SAMPLE: saveSample(); break; case SampleChange.KILL: killAll(); break; case SampleChange.BUILD_NEXT: buildNextBuffer(msg.arg1, msg.arg2); break; } } }; Looper.loop(); } private void loadAudioData() { try { int nRead; InputStream stream; ByteArrayOutputStream buffer; // Load all possible clips into memory for (int i = 0; i < audioClips.length; i++) { buffer = new ByteArrayOutputStream(); stream = context.getResources().openRawResource(audioClips[i].id); byte[] tempBuffer = new byte[stream.available() - 44]; while ((nRead = stream.read(tempBuffer, WavStream.HEADER_SIZE, tempBuffer.length - WavStream.HEADER_SIZE)) != -1) { buffer.write(tempBuffer, 0, nRead); } audioClips[i].audioBuffer = tempBuffer.clone(); } } catch (IOException e) { } } private void adjustVolume(int channel, int level) { // TODO - Implement the shit } private void adjustPitch(int channel, int pitch) { // TODO - Implement the shit } private void adjustTempo(int channel, int tempo) { // TODO - Implement the shit } private void addScratch(Object object) { // TODO - Implement the shit } private void addClip(Object obj) { if (obj == null) { Log.d(TAG, "obj was null"); } if (channels.size() < 9) { AudioChannel newClip = (AudioChannel)obj; newClip.volume = 0; newClip.pitch = 0; for (int i = 0; i < audioClips.length; i++) { if (audioClips[i].id == newClip.id) { newClip.buildMeasures(audioClips[i].audioBuffer); } } channels.add(newClip); if (!streaming) { buildNextBuffer(0, 0); } } } private void removeChannel(int channel) { // TODO - Implement the shit } private void saveSample() { // TODO - Implement the shit } private void killAll() { // TODO - Implement the shit } private void buildNextBuffer(int forMeasure, int forDownBeat) { try { if (!streaming) { // Set up piped streamed to UI thread stream = new PipedOutputStream(); // Pipe is able to handle one measure at a time PipedInputStream inputStream = new PipedInputStream(stream, (WavStream.SAMPLE_SIZE / 2)); activityCallback.onPipeReady(inputStream); // Build the first buffer int firstChunkSize = WavStream.CHUNK_SIZE + WavStream.HEADER_SIZE; byte[] firstChunk = new byte[firstChunkSize]; // Slap the wav header in wavHeader = new byte[WavStream.HEADER_SIZE]; for (int i = 0; i < wavHeader.length; i++) { firstChunk[i] = wavHeader[i]; } // Fill in an int array with all the files combined int clipsAdded = 0; int dataPos = 0; int[] tempData = new int[firstChunk.length - WavStream.HEADER_SIZE]; for (int i = 0; i < channels.size(); i++) { AudioChannel clip = channels.get(i); for (int measure = 0; measure < 1; measure++) { for (int downBeat = 0; downBeat < 1; downBeat++) { for (int j = 0; j < clip.measureBreakdown[measure][downBeat].length; j++) { tempData[dataPos] += clip.measureBreakdown[measure][downBeat][j]; dataPos++; } } } clipsAdded++; } // Combine all the tracks for (int i = WavStream.HEADER_SIZE; i < firstChunk.length; i++) { firstChunk[i] = (byte)(tempData[i - WavStream.HEADER_SIZE] / clipsAdded); } // Write buffer to stream stream.write(firstChunk, 0, firstChunk.length); stream.flush(); streaming = true; // Notify Activty to start playing audio activityCallback.onBufferStart(firstChunk.length); } else { int[] audioData = new int[WavStream.CHUNK_SIZE]; Arrays.fill(audioData, (byte)0); // Gather all the audioData int numChannels = channels.size(); int tracksAdded = 0; for (int i = 0; i < numChannels; i++) { AudioChannel clip = channels.get(i); for (int j = 0; j < clip.measureBreakdown[forMeasure][forDownBeat].length; j++) { audioData[j] += clip.measureBreakdown[forMeasure][forDownBeat][j]; } tracksAdded++; } // Layer audio byte[] nextChunk = new byte[audioData.length]; for (int i = 0; i < nextChunk.length; i++) { nextChunk[i] = (byte)(audioData[i] / tracksAdded); } // Write it to the stream stream.write(nextChunk, 0, nextChunk.length); stream.flush(); activityCallback.onNextBuffer(nextChunk.length); } } catch (Exception e) { e.printStackTrace(); } } }