Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wave Generator: Implement option to generate waves without PSLab Device #1976

Draft
wants to merge 1 commit into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 108 additions & 30 deletions app/src/main/java/io/pslab/activity/WaveGeneratorActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationManager;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
Expand Down Expand Up @@ -140,6 +141,8 @@ public class WaveGeneratorActivity extends AppCompatActivity {
Button btnAnalogMode;
@BindView(R.id.digital_mode_btn)
Button btnDigitalMode;
@BindView(R.id.use_phone_btn)
Button btnUsePhone;
@BindView(R.id.pwm_btn_freq)
Button pwmBtnFreq;
@BindView(R.id.pwm_btn_duty)
Expand Down Expand Up @@ -187,7 +190,9 @@ public class WaveGeneratorActivity extends AppCompatActivity {
private RelativeLayout squareModeControls;
private LineChart previewChart;
private boolean isPlayingSound = false;
private boolean usePhone = false;
private ProduceSoundTask produceSoundTask;
private GenerateWavesFromPhoneTask generateWavesFromPhoneTask;

@SuppressLint("ClickableViewAccessibility")
@Override
Expand Down Expand Up @@ -334,6 +339,24 @@ public void onClick(View v) {
}
});

btnUsePhone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
usePhone = !usePhone;
if(usePhone) {
if(isPlayingSound) {
btnProduceSound.callOnClick();
}
btnUsePhone.setText(R.string.text_use_pslab);
generateWavesFromPhoneTask = new GenerateWavesFromPhoneTask(WaveGeneratorActivity.this);
generateWavesFromPhoneTask.execute();
} else {
btnUsePhone.setText(R.string.text_use_phone);
generateWavesFromPhoneTask.cancel(true);
}
}
});

btnPwmSq1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Expand Down Expand Up @@ -1282,6 +1305,42 @@ public void recordSensorData(RealmObject sensorData) {
realm.commitTransaction();
}

/**
* Samples a wave into an AudioTrack instance. Useful for either playing sound or pushing the signal
* through the headphone jack.
*
*/
public void sampleWaveIntoAudioTrack(AudioTrack track, int sampleRateInHz, int bufferLength, AsyncTask asyncTask) {
assert(track != null);

short[] buffer = new short[bufferLength];
float angle = 0;
float samples[] = new float[bufferLength];
double frequency;

while(!asyncTask.isCancelled()) {
if (WaveGeneratorCommon.mode_selected == WaveConst.SQUARE) {
frequency = WaveGeneratorCommon.wave.get(waveBtnActive).get(WaveConst.FREQUENCY);
} else {
frequency = WaveGeneratorCommon.wave.get(WaveConst.SQR1).get(WaveConst.FREQUENCY);
}
float increment = (float) ((2 * Math.PI) * frequency / sampleRateInHz);
for (int i = 0; i < samples.length; i++) {
samples[i] = (float) Math.sin(angle);
if (WaveGeneratorCommon.mode_selected == WaveConst.PWM) {
samples[i] = (samples[i] >= 0.0) ? 1 : -1;
} else {
if (WaveGeneratorCommon.wave.get(waveBtnActive).get(WaveConst.WAVETYPE) == 2) {
samples[i] = (float) ((2 / Math.PI) * Math.asin(samples[i]));
}
}
buffer[i] = (short) (samples[i] * Short.MAX_VALUE);
angle += increment;
}
track.write(buffer, 0, buffer.length);
}
}

public enum WaveConst {WAVETYPE, WAVE1, WAVE2, SQR1, SQR2, SQR3, SQR4, FREQUENCY, PHASE, DUTY, SQUARE, PWM}

public enum WaveData {
Expand All @@ -1300,47 +1359,66 @@ public final int getValue() {

private class ProduceSoundTask extends AsyncTask<Void, Void, Void> {

private AudioTrack track;
final int sampleRateInHz = 44100;
final int bufferLength = 1024;
private AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferLength, AudioTrack.MODE_STREAM);

@Override
protected Void doInBackground(Void... voids) {
short[] buffer = new short[1024];
track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, buffer.length, AudioTrack.MODE_STREAM);
float angle = 0;
float samples[] = new float[1024];

track.play();
double frequency;
while (isPlayingSound) {
if (WaveGeneratorCommon.mode_selected == WaveConst.SQUARE) {
frequency = WaveGeneratorCommon.wave.get(waveBtnActive).get(WaveConst.FREQUENCY);
} else {
frequency = WaveGeneratorCommon.wave.get(WaveConst.SQR1).get(WaveConst.FREQUENCY);
}
float increment = (float) ((2 * Math.PI) * frequency / 44100);
for (int i = 0; i < samples.length; i++) {
samples[i] = (float) Math.sin(angle);
if (WaveGeneratorCommon.mode_selected == WaveConst.PWM) {
samples[i] = (samples[i] >= 0.0) ? 1 : -1;
} else {
if (WaveGeneratorCommon.wave.get(waveBtnActive).get(WaveConst.WAVETYPE) == 2) {
samples[i] = (float) ((2 / Math.PI) * Math.asin(samples[i]));
}
}
buffer[i] = (short) (samples[i] * Short.MAX_VALUE);
angle += increment;
}
track.write(buffer, 0, buffer.length);
}
sampleWaveIntoAudioTrack(track, sampleRateInHz, bufferLength, this);
track.flush();
track.stop();
track.release();
return null;
}
}

private class GenerateWavesFromPhoneTask extends AsyncTask<Void, Void, Void> {

WaveGeneratorActivity activity = null;
final int sampleRateInHz = 44100;
final int bufferLength = 1024;
private AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferLength, AudioTrack.MODE_STREAM);

public GenerateWavesFromPhoneTask(WaveGeneratorActivity activity) {
this.activity = activity;
}

@Override
protected void onCancelled() {
super.onCancelled();
protected Void doInBackground(Void... voids) {
boolean wired = false;
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
AudioDeviceInfo[] audioDevices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
for(AudioDeviceInfo deviceInfo : audioDevices){
if(deviceInfo.getType()==AudioDeviceInfo.TYPE_WIRED_HEADPHONES
|| deviceInfo.getType()==AudioDeviceInfo.TYPE_WIRED_HEADSET){
wired = true;
break;
}
}
if(!wired) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), R.string.text_not_wired,Toast.LENGTH_SHORT).show();
}
});
return null;
}
track.play();
sampleWaveIntoAudioTrack(track, sampleRateInHz, bufferLength, this);
track.flush();
track.stop();
track.release();
return null;
}

@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
activity.usePhone = false;
activity.btnUsePhone.setText(R.string.text_use_phone);
}
}
}
17 changes: 17 additions & 0 deletions app/src/main/res/layout/wave_generator_main_controls.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,21 @@
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="@dimen/wave_gen_control_text_size" />

<Button
android:id="@+id/use_phone_btn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/margin_btn"
android:layout_marginTop="@dimen/margin_btn"
android:layout_marginEnd="@dimen/margin_btn"
android:layout_marginBottom="@dimen/margin_btn"
android:layout_weight="1"
android:background="@drawable/btn_back_rounded"
android:minWidth="@dimen/btn_min_width"
android:stateListAnimator="@animator/selector_animator"
android:text="@string/text_use_phone"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="@dimen/wave_gen_control_text_size" />
</LinearLayout>
4 changes: 3 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,9 @@
<string name="duty_cycle">Duty Cycle:</string>
<string name="mode">Mode</string>
<string name="text_digital">Digital</string>

<string name="text_use_phone">Use Phone</string>
<string name="text_use_pslab">Use PSLab</string>
<string name="text_not_wired">Nothing plugged in the headphone jack</string>
<string name="text_connected">Connected</string>
<string name="text_disconnected">Disconnected</string>

Expand Down