We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi all. I am having fun using Processing for Android to program my SBC which is running Andoid 4.4. I have a project I am working on that involves playing some sine waves and using an accelerometer to change the frequency. The code I am using to produce the sinewaves is from a theremin project I found on the web and uses a runnable class to call the audiotrack object. The code is here:
`public class tonebox implements Runnable {
// If you change this, then you will have to adjust some of the // other cyclic factors as well, notably warble. Sample length // makes for more nimble tone changes. public int sampleLength = 64; // This is the frequency max. Most examples show 44100, but this // only invites static. We never climb above about 3000 so this // could even be set lower. public int freqRange = 11025;
// 1 to maxTones independent tones public int maxTones = 6; private int howl = 1; private boolean fuzz = false;
private double warbMag = 0.0; private double warbFreq = 0.0; // range in hertz, suggest 200 to 2500 private double freq = 0.0; private double volume = 0.0; private boolean go = true; private boolean finished = false;
AudioTrack Track;//= new AudioTrack(AudioManager.STREAM_MUSIC, // freqRange, AudioFormat.CHANNEL_CONFIGURATION_MONO, // AudioFormat.ENCODING_PCM_16BIT, sampleLength, // AudioTrack.MODE_STATIC);;
// magnitude of warble oscillation, suggest 0.0 to 50 public synchronized void warbleMagnitude(int wm) {
warbMag = (double) wm;
}
// suggest 0.0 to 0.15 public synchronized void warbleFrequency(double wf) {
warbFreq = wf;
}
public synchronized void frequency(int fr) {
freq = (double) fr;
}
// volume is 0.0 to 1.0 public synchronized void volume(double vol) {
volume = vol;
}
public void start(boolean g) {
go = g;
}
public synchronized void howl(int h) {
howl = h;
}
public void run() {
short samples[] = new short[sampleLength];
double freqBase[] = new double[maxTones];
int freqTrack[] = new int[maxTones];
int freqVector[] = new int[maxTones];
double angle[] = new double[maxTones];
double collectedAngle;
double computedWarble = 0;
int fuzzBase;
Random gen = new Random();
// set up audio Track and start it
int minSize = AudioTrack.getMinBufferSize(
freqRange, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );
Track = new AudioTrack( AudioManager.STREAM_MUSIC, freqRange,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minSize, AudioTrack.MODE_STREAM);
Track.play();
// feed it samples
while (!finished) {
if (go) {
// compute the base sample frequency
freqBase[0] = freq + warbMag * Math.sin(computedWarble);
// append any additional harmonics
for ( int i = 1; i < howl; i++) {
freqVector[i] += gen.nextInt(3) - 1;
if ( Math.abs(freqVector[i]) > 6 ) freqVector[i] = (int) (freqVector[i] / 2);
freqTrack[i] += freqVector[i];
if ( Math.abs(freqTrack[i]) > 100) freqVector[i] = -freqVector[i];
freqBase[i] = freqBase[0] + freqTrack[i];
}
// fill sample
for (int i = 0; i < sampleLength; i++ ) {
collectedAngle = 0;
// compute base tone and then append any additional
for ( int j = 0; j < howl; j++) {
// for fuzz, compute a parabolic random displacement
if (fuzz) {
fuzzBase = 0;
for (int k = 0; k < 5; k++)
fuzzBase += gen.nextInt(15);
freqBase[j] += fuzzBase - 35;
}
angle[j] += 2 * Math.PI * freqBase[j] / freqRange;
if (angle[j] > (2 * Math.PI))
angle[j] -= (2 * Math.PI);
collectedAngle += Math.sin(angle[j]);
}
samples[i] = (short) ((collectedAngle / howl) * Short.MAX_VALUE * volume);
}
// advance warble
computedWarble += warbFreq;
if (computedWarble > (2 * Math.PI)) {
computedWarble -= (2 * Math.PI);
}
// shove the sample into the stream
Track.write(samples, 0, sampleLength);
go2=go;
}
else {
// wait when stopped
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} }`
It is easy to use. I set up frequency and volume in void setup() and call the run() method in void draw() It plays.
I also want to read some accelerometer values so have a function to call a bash script on my Android device. The code is here:
`void readaccel() { // what command to run String commandToRun = "mpu-6050-getbyte 3b"; // String commandToRun = "ls"; // String commandToRun = "wc -w sourcefile.extension"; // String commandToRun = "cp sourcefile.extension destinationfile.extension"; // String commandToRun = "./yourBashScript.sh";
File workingDir = new File("/system/bin/"); // where to do it - should be full path String returnedValues; // value to return any results
// give us some info:
// println("Running command: " + commandToRun); // println("Location: " + workingDir); // println("---------------------------------------------\n");
try {
// complicated! basically, we have to load the exec command within Java's Runtime
// exec asks for 1. command to run, 2. null which essentially tells Processing to
// inherit the environment settings from the current setup (I am a bit confused on
// this so it seems best to leave it), and 3. location to work (full path is best)
Process p = Runtime.getRuntime().exec(commandToRun, null, workingDir);
// variable to check if we've received confirmation of the command
int i = p.waitFor();
// if we have an output, print to screen
if (i==0 ) {
// BufferedReader used to get values back from the command
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
// read the output from the command
while ( (returnedValues = stdInput.readLine ()) != null) {
println(returnedValues);
x=((returnedValues));
// xcoord=Integer.parseInt(returnedValues,2);
}
}
// if there are any error messages but we can still get an output, they print here
else {
BufferedReader stdErr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
// if something is returned (ie: not null) print the result
while ( (returnedValues = stdErr.readLine ()) != null) {
println(returnedValues);
}
}
// box.run();
}
// if there is an error, let us know
catch (Exception e) {
println("Error running command!");
println(e);
}
}`
It works fine but when I try to run both the audiotrack class and the accelerometer reader in draw(), audiotrack blocks the accelerometer process. I'm not up on threads but could someone please help me work out how to run both processes at the same time?
Thanks. Steve.S
p.s. i dont know why my code isn't being formatted properly. sorry.
Answers
Here's how:
http://forum.processing.org/two/discussion/8045/how-to-format-code-and-text
@mubase== write() from audioTrack is blocking line 84; perhaps you can use :: write(ByteBuffer audioData, int sizeInBytes, int writeMode) with writeMode flag set to WRITE_NON_BLOCKING....