9
9
import android .graphics .drawable .Drawable ;
10
10
import android .location .Location ;
11
11
import android .location .LocationManager ;
12
+ import android .media .AudioDeviceInfo ;
12
13
import android .media .AudioFormat ;
13
14
import android .media .AudioManager ;
14
15
import android .media .AudioTrack ;
@@ -140,6 +141,8 @@ public class WaveGeneratorActivity extends AppCompatActivity {
140
141
Button btnAnalogMode ;
141
142
@ BindView (R .id .digital_mode_btn )
142
143
Button btnDigitalMode ;
144
+ @ BindView (R .id .use_phone_btn )
145
+ Button btnUsePhone ;
143
146
@ BindView (R .id .pwm_btn_freq )
144
147
Button pwmBtnFreq ;
145
148
@ BindView (R .id .pwm_btn_duty )
@@ -187,7 +190,9 @@ public class WaveGeneratorActivity extends AppCompatActivity {
187
190
private RelativeLayout squareModeControls ;
188
191
private LineChart previewChart ;
189
192
private boolean isPlayingSound = false ;
193
+ private boolean usePhone = false ;
190
194
private ProduceSoundTask produceSoundTask ;
195
+ private GenerateWavesFromPhoneTask generateWavesFromPhoneTask ;
191
196
192
197
@ SuppressLint ("ClickableViewAccessibility" )
193
198
@ Override
@@ -334,6 +339,21 @@ public void onClick(View v) {
334
339
}
335
340
});
336
341
342
+ btnUsePhone .setOnClickListener (new View .OnClickListener () {
343
+ @ Override
344
+ public void onClick (View v ) {
345
+ usePhone = !usePhone ;
346
+ if (usePhone ) {
347
+ btnUsePhone .setText (R .string .text_use_pslab );
348
+ generateWavesFromPhoneTask = new GenerateWavesFromPhoneTask (WaveGeneratorActivity .this );
349
+ generateWavesFromPhoneTask .execute ();
350
+ } else {
351
+ btnUsePhone .setText (R .string .text_use_phone );
352
+ generateWavesFromPhoneTask .cancel (true );
353
+ }
354
+ }
355
+ });
356
+
337
357
btnPwmSq1 .setOnClickListener (new View .OnClickListener () {
338
358
@ Override
339
359
public void onClick (View view ) {
@@ -1282,6 +1302,42 @@ public void recordSensorData(RealmObject sensorData) {
1282
1302
realm .commitTransaction ();
1283
1303
}
1284
1304
1305
+ /**
1306
+ * Samples a wave into an AudioTrack instance. Useful for either playing sound or pushing the signal
1307
+ * through the headphone jack.
1308
+ *
1309
+ */
1310
+ public void sampleWaveIntoAudioTrack (AudioTrack track , int sampleRateInHz , int bufferLength ) {
1311
+ assert (track != null );
1312
+
1313
+ short [] buffer = new short [bufferLength ];
1314
+ float angle = 0 ;
1315
+ float samples [] = new float [bufferLength ];
1316
+ double frequency ;
1317
+
1318
+ while (true ) {
1319
+ if (WaveGeneratorCommon .mode_selected == WaveConst .SQUARE ) {
1320
+ frequency = WaveGeneratorCommon .wave .get (waveBtnActive ).get (WaveConst .FREQUENCY );
1321
+ } else {
1322
+ frequency = WaveGeneratorCommon .wave .get (WaveConst .SQR1 ).get (WaveConst .FREQUENCY );
1323
+ }
1324
+ float increment = (float ) ((2 * Math .PI ) * frequency / sampleRateInHz );
1325
+ for (int i = 0 ; i < samples .length ; i ++) {
1326
+ samples [i ] = (float ) Math .sin (angle );
1327
+ if (WaveGeneratorCommon .mode_selected == WaveConst .PWM ) {
1328
+ samples [i ] = (samples [i ] >= 0.0 ) ? 1 : -1 ;
1329
+ } else {
1330
+ if (WaveGeneratorCommon .wave .get (waveBtnActive ).get (WaveConst .WAVETYPE ) == 2 ) {
1331
+ samples [i ] = (float ) ((2 / Math .PI ) * Math .asin (samples [i ]));
1332
+ }
1333
+ }
1334
+ buffer [i ] = (short ) (samples [i ] * Short .MAX_VALUE );
1335
+ angle += increment ;
1336
+ }
1337
+ track .write (buffer , 0 , buffer .length );
1338
+ }
1339
+ }
1340
+
1285
1341
public enum WaveConst {WAVETYPE , WAVE1 , WAVE2 , SQR1 , SQR2 , SQR3 , SQR4 , FREQUENCY , PHASE , DUTY , SQUARE , PWM }
1286
1342
1287
1343
public enum WaveData {
@@ -1300,47 +1356,94 @@ public final int getValue() {
1300
1356
1301
1357
private class ProduceSoundTask extends AsyncTask <Void , Void , Void > {
1302
1358
1303
- private AudioTrack track ;
1359
+ final int sampleRateInHz = 44100 ;
1360
+ final int bufferLength = 1024 ;
1361
+ private AudioTrack track = new AudioTrack (AudioManager .STREAM_MUSIC , sampleRateInHz , AudioFormat .CHANNEL_CONFIGURATION_MONO , AudioFormat .ENCODING_PCM_16BIT , bufferLength , AudioTrack .MODE_STREAM );
1362
+ private Thread thread = new Thread (new Runnable () {
1363
+ @ Override
1364
+ public void run () {
1365
+ track .play ();
1366
+ sampleWaveIntoAudioTrack (track , sampleRateInHz , bufferLength );
1367
+ }
1368
+ });
1304
1369
1305
1370
@ Override
1306
1371
protected Void doInBackground (Void ... voids ) {
1307
- short [] buffer = new short [1024 ];
1308
- track = new AudioTrack (AudioManager .STREAM_MUSIC , 44100 , AudioFormat .CHANNEL_CONFIGURATION_MONO , AudioFormat .ENCODING_PCM_16BIT , buffer .length , AudioTrack .MODE_STREAM );
1309
- float angle = 0 ;
1310
- float samples [] = new float [1024 ];
1311
-
1312
- track .play ();
1313
- double frequency ;
1314
- while (isPlayingSound ) {
1315
- if (WaveGeneratorCommon .mode_selected == WaveConst .SQUARE ) {
1316
- frequency = WaveGeneratorCommon .wave .get (waveBtnActive ).get (WaveConst .FREQUENCY );
1317
- } else {
1318
- frequency = WaveGeneratorCommon .wave .get (WaveConst .SQR1 ).get (WaveConst .FREQUENCY );
1372
+ thread .start ();
1373
+ while (isPlayingSound ) {} /* loop until button is unselected */
1374
+ thread .interrupt ();
1375
+ return null ;
1376
+ }
1377
+
1378
+ @ Override
1379
+ protected void onCancelled () {
1380
+ super .onCancelled ();
1381
+ thread .interrupt ();
1382
+ track .flush ();
1383
+ track .stop ();
1384
+ track .release ();
1385
+ }
1386
+ }
1387
+
1388
+ private class GenerateWavesFromPhoneTask extends AsyncTask <Void , Void , Void > {
1389
+
1390
+ WaveGeneratorActivity activity = null ;
1391
+ final int sampleRateInHz = 44100 ;
1392
+ final int bufferLength = 1024 ;
1393
+ private AudioTrack track = new AudioTrack (AudioManager .STREAM_MUSIC , sampleRateInHz , AudioFormat .CHANNEL_CONFIGURATION_MONO , AudioFormat .ENCODING_PCM_16BIT , bufferLength , AudioTrack .MODE_STREAM );
1394
+ private Thread thread = new Thread (new Runnable () {
1395
+ @ Override
1396
+ public void run () {
1397
+ track .play ();
1398
+ sampleWaveIntoAudioTrack (track , sampleRateInHz , bufferLength );
1399
+ }
1400
+ });
1401
+
1402
+ public GenerateWavesFromPhoneTask (WaveGeneratorActivity activity ) {
1403
+ this .activity = activity ;
1404
+ }
1405
+
1406
+ @ Override
1407
+ protected Void doInBackground (Void ... voids ) {
1408
+ boolean wired = false ;
1409
+ AudioManager audioManager = (AudioManager )getSystemService (Context .AUDIO_SERVICE );
1410
+ AudioDeviceInfo [] audioDevices = audioManager .getDevices (AudioManager .GET_DEVICES_ALL );
1411
+ for (AudioDeviceInfo deviceInfo : audioDevices ){
1412
+ if (deviceInfo .getType ()==AudioDeviceInfo .TYPE_WIRED_HEADPHONES
1413
+ || deviceInfo .getType ()==AudioDeviceInfo .TYPE_WIRED_HEADSET ){
1414
+ wired = true ;
1415
+ break ;
1319
1416
}
1320
- float increment = (float ) ((2 * Math .PI ) * frequency / 44100 );
1321
- for (int i = 0 ; i < samples .length ; i ++) {
1322
- samples [i ] = (float ) Math .sin (angle );
1323
- if (WaveGeneratorCommon .mode_selected == WaveConst .PWM ) {
1324
- samples [i ] = (samples [i ] >= 0.0 ) ? 1 : -1 ;
1325
- } else {
1326
- if (WaveGeneratorCommon .wave .get (waveBtnActive ).get (WaveConst .WAVETYPE ) == 2 ) {
1327
- samples [i ] = (float ) ((2 / Math .PI ) * Math .asin (samples [i ]));
1328
- }
1417
+ }
1418
+ if (!wired ) {
1419
+ activity .runOnUiThread (new Runnable () {
1420
+ @ Override
1421
+ public void run () {
1422
+ Toast .makeText (getApplicationContext (), R .string .text_not_wired ,Toast .LENGTH_SHORT ).show ();
1329
1423
}
1330
- buffer [i ] = (short ) (samples [i ] * Short .MAX_VALUE );
1331
- angle += increment ;
1332
- }
1333
- track .write (buffer , 0 , buffer .length );
1424
+ });
1425
+ return null ;
1334
1426
}
1427
+ thread .start ();
1428
+ while (usePhone ) {} /* loop until button is unselected */
1429
+ thread .interrupt ();
1335
1430
return null ;
1336
1431
}
1337
1432
1338
1433
@ Override
1339
1434
protected void onCancelled () {
1340
1435
super .onCancelled ();
1436
+ thread .interrupt ();
1341
1437
track .flush ();
1342
1438
track .stop ();
1343
1439
track .release ();
1344
1440
}
1441
+
1442
+ @ Override
1443
+ protected void onPostExecute (Void aVoid ) {
1444
+ super .onPostExecute (aVoid );
1445
+ activity .usePhone = false ;
1446
+ activity .btnUsePhone .setText (R .string .text_use_phone );
1447
+ }
1345
1448
}
1346
1449
}
0 commit comments