Android Open Source - android-wav-mixer Mixer






From Project

Back to project page android-wav-mixer.

License

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.

Java Source Code

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




Java Source Code List

com.nathansizemore.beatmaker.AttractActivity.java
com.nathansizemore.beatmaker.ClipSelectActivity.java
com.nathansizemore.beatmaker.audiomixer.AudioChannel.java
com.nathansizemore.beatmaker.audiomixer.ClipAddEvent.java
com.nathansizemore.beatmaker.audiomixer.Clip.java
com.nathansizemore.beatmaker.audiomixer.Mixer.java
com.nathansizemore.beatmaker.audiomixer.Sample.java
com.nathansizemore.beatmaker.audiomixer.extras.MixerStatus.java
com.nathansizemore.beatmaker.audiomixer.extras.SampleChange.java
com.nathansizemore.beatmaker.audiomixer.extras.WavStream.java
com.nathansizemore.beatmaker.audiomixer.extras.package-info.java
com.nathansizemore.beatmaker.audiomixer.package-info.java
com.nathansizemore.beatmaker.bluetooth.package-info.java
com.nathansizemore.beatmaker.fragments.MainAttract.java
com.nathansizemore.beatmaker.fragments.MainClipSelect.java
com.nathansizemore.beatmaker.fragments.interfaces.AttractScreenTouch.java
com.nathansizemore.beatmaker.fragments.interfaces.SampleSelect.java
com.nathansizemore.beatmaker.fragments.interfaces.package-info.java
com.nathansizemore.beatmaker.fragments.package-info.java