Skip to content
Open
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
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

77 changes: 77 additions & 0 deletions app/src/main/java/com/example/fishe/project_cs3218/FFT.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.example.fishe.project_cs3218

import android.graphics.Bitmap
import com.example.fishe.project_cs3218.MainActivity.Companion.FFT_Len
import com.example.fishe.project_cs3218.MainActivity.Companion.mx
import com.example.fishe.project_cs3218.MainActivity.Companion.soundFFTMag
import com.example.fishe.project_cs3218.R.id.surfaceView
import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D

class FFT(activity: MainActivity) {

private var soundFFT: DoubleArray = DoubleArray(1024)

private var soundFFTTemp: DoubleArray = DoubleArray(1024)
private var mxIntensity: Double = 0.toDouble()
private var soundSegmented: IntArray = intArrayOf(1024) // dummy initialization
private var soundBuffer: ShortArray? = null
private var soundBackgroundImage: Bitmap? = null

//----------- perform FFT
fun runFFT() {
var fftThread: Thread? = null

soundBuffer = ShortArray(1024)
soundBackgroundImage = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
soundSegmented = IntArray(FFT_Len)
soundFFT = DoubleArray(FFT_Len * 2)
soundFFTMag = DoubleArray(FFT_Len)
soundFFTTemp = DoubleArray(FFT_Len * 2)

fftThread = object : Thread() {
override fun run() {
while (true) {
performFFT()
}
}
}
fftThread!!.start()
}

fun performFFT() {


for (i in 0..FFT_Len - 1) {
soundFFT[i * 2] = MainActivity.buffer[i].toDouble()
soundFFT[i * 2 + 1] = 0.0
}

val fft = DoubleFFT_1D(FFT_Len)
fft.complexForward(soundFFT)

// perform fftshift here
for (i in 0 until FFT_Len) {
soundFFTTemp[i] = soundFFT[i + FFT_Len]
soundFFTTemp[i + FFT_Len] = soundFFT[i]
}
for (i in 0 until FFT_Len * 2) {
soundFFT[i] = soundFFTTemp[i]
}

mx = -99999.0
for (i in 0 until FFT_Len) {
val re = soundFFT[2 * i]
val im = soundFFT[2 * i + 1]
soundFFTMag[i] = Math.log(re * re + im * im + 0.001)
if (soundFFTMag[i] > mx) mx = soundFFTMag[i]
}

// normalize
/*for (i in 0 until FFT_Len) {
soundFFTMag[i] = height * 4 / 5 - soundFFTMag[i] / mx * 500
}*/

mxIntensity = mx
}

}
62 changes: 48 additions & 14 deletions app/src/main/java/com/example/fishe/project_cs3218/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,33 @@ import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

private val RECORD_AUDIO_REQUEST_CODE = 101

lateinit private var soundSampler: SoundSampler
lateinit private var soundSampler: SoundReceiver
lateinit private var soundTransmitter: SoundTransmitter

companion object {
lateinit var buffer: ShortArray
lateinit var soundFFTMag: DoubleArray

var bufferSize: Int = 0 // in bytes
var FFT_Len = 1024
var bufferSize: Int = 0 // in bytes, will be altered in SoundReceiver.ktt

const val FS = 44100 // sampling frequency
var mx = -99999.0
var freqResolution: Double = FS * 1.0 / FFT_Len

const val offset = 21 //lower frequency is not used for coded because noises usually are in low frequencies
const val bytePerSoundSignal = 16
const val freqResolutionPerByte = 25


var threshold = 9999.9
var message: String = "hi"
}


Expand All @@ -27,13 +43,32 @@ class MainActivity : AppCompatActivity() {

// seek permission to do audio recording
setupPermissions()
initiateSoundTransmitting()

sendButton?.setOnClickListener {
val x: String? = textMessage?.text.toString()
val charset = Charsets.UTF_8

if (x.isNullOrBlank()) {
textMessage?.error = "Empty Message"
textMessage?.requestFocus()
return@setOnClickListener
}
textMessage!!.text.clear()

val byteArray = x?.toByteArray(charset)
Toast.makeText(this, byteArray?.contentToString() , Toast.LENGTH_LONG)
.show()
//textView.text = byteArray?.toString(charset)
textView.text = message
soundTransmitter.playSound(byteArray)
}
}

override fun onStart() {
super.onStart()
initiateSoundSampling()
//initiateFFT()
}


Expand All @@ -59,7 +94,6 @@ class MainActivity : AppCompatActivity() {
RECORD_AUDIO_REQUEST_CODE)
}


override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
Expand All @@ -70,32 +104,32 @@ class MainActivity : AppCompatActivity() {
Log.i("tag", "Permission has been denied by user")
} else {
Log.i("tag", "Permission has been granted by user")


}
}
}
}


fun initiateSoundSampling(){
private fun initiateSoundSampling(){
try {
soundSampler = SoundSampler(this)
soundSampler = SoundReceiver(this)

} catch (e: Exception) {
Toast.makeText(applicationContext, "Cannot instantiate SoundSampler", Toast.LENGTH_LONG).show()
Toast.makeText(applicationContext, "Cannot instantiate SoundReceiver", Toast.LENGTH_LONG).show()
}

try {
soundSampler.init()
} catch (e: Exception) {
Toast.makeText(applicationContext, "Cannot initialize SoundSampler.", Toast.LENGTH_LONG).show()
Toast.makeText(applicationContext, "Cannot initialize SoundReceiver.", Toast.LENGTH_LONG).show()
}


Toast.makeText(this, "bufferSize = " +bufferSize, Toast.LENGTH_SHORT).show()
Toast.makeText(this, "buffer.size = " +buffer.size, Toast.LENGTH_SHORT).show()

}

private fun initiateSoundTransmitting() {
try {
soundTransmitter = SoundTransmitter(this)
} catch (e: Exception) {
Toast.makeText(applicationContext, "Cannot instantiate SoundTransmitter", Toast.LENGTH_LONG).show()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.util.Half.toFloat
import android.view.MotionEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
import com.example.fishe.project_cs3218.MainActivity.Companion.FFT_Len
import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D
import com.example.fishe.project_cs3218.MainActivity.Companion.bufferSize
import com.example.fishe.project_cs3218.MainActivity.Companion.buffer
import com.example.fishe.project_cs3218.MainActivity.Companion.mx
import com.example.fishe.project_cs3218.MainActivity.Companion.soundFFTMag
import java.util.*
import java.util.concurrent.Executors

Expand All @@ -25,24 +29,10 @@ class MySurfaceView : SurfaceView, SurfaceHolder.Callback {

private var line_width : Float = 6f

private var soundBackgroundImage: Bitmap? = null
private var soundBuffer: ShortArray? = null
private var soundSegmented: IntArray = intArrayOf(1024) // dummy initialization


private var soundFFT: DoubleArray = DoubleArray(1024)

private var soundFFTMag: DoubleArray = DoubleArray(1024)
private var soundFFTTemp: DoubleArray = DoubleArray(1024)

var FFT_Len = 512

private var soundLinePaint: Paint? = null
private var soundLinePaint2: Paint? = null
private var soundLinePaint3: Paint? = null

private var mxIntensity: Double = 0.toDouble()


constructor(context: Context) : super(context) {
initialize()
Expand Down Expand Up @@ -90,15 +80,6 @@ class MySurfaceView : SurfaceView, SurfaceHolder.Callback {
soundLinePaint3!!.setARGB(255, 0, 255, 255)
soundLinePaint3!!.strokeWidth = 3f

soundBuffer = ShortArray(1024)

soundBackgroundImage = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)

soundSegmented = IntArray(FFT_Len)
soundFFT = DoubleArray(FFT_Len * 2)
soundFFTMag = DoubleArray(FFT_Len)
soundFFTTemp = DoubleArray(FFT_Len * 2)

drawFlag = true

}
Expand All @@ -125,7 +106,7 @@ class MySurfaceView : SurfaceView, SurfaceHolder.Callback {
//----------- plot the sound wave

val yOffset = 200.0f
val yScale = 0.1f
val yScale = 0.02f

var prevX = 0.0f
var prevY: Float = buffer[0].toFloat() * yScale
Expand All @@ -142,48 +123,18 @@ class MySurfaceView : SurfaceView, SurfaceHolder.Callback {

}

//----------- perform FFT

for (i in 0..FFT_Len - 1) {
soundFFT[i * 2] = buffer[i].toDouble()
soundFFT[i * 2 + 1] = 0.0
}

val fft = DoubleFFT_1D(FFT_Len)
fft.complexForward(soundFFT)

// perform fftshift here
for (i in 0 until FFT_Len) {
soundFFTTemp[i] = soundFFT[i + FFT_Len]
soundFFTTemp[i + FFT_Len] = soundFFT[i]
}
for (i in 0 until FFT_Len * 2) {
soundFFT[i] = soundFFTTemp[i]
}

var mx = -99999.0
for (i in 0 until FFT_Len) {
val re = soundFFT[2 * i]
val im = soundFFT[2 * i + 1]
soundFFTMag[i] = Math.log(re * re + im * im + 0.001)
if (soundFFTMag[i] > mx) mx = soundFFTMag[i]
}

// normalize
for (i in 0 until FFT_Len) {
soundFFTMag[i] = height * 4 / 5 - soundFFTMag[i] / mx * 500
}

mxIntensity = mx


// display the fft results
val xStepSz = 1
// draw the vertical axis (at DC location)
c.drawLine((FFT_Len / 2).toFloat(), height.toFloat(), (FFT_Len / 2).toFloat(), 0f, soundLinePaint3)
var i = 0
while (i < FFT_Len - 1) {
c.drawLine((i / xStepSz).toFloat(), soundFFTMag[i].toInt().toFloat(), (i / xStepSz + 1).toFloat(), soundFFTMag[i + 1].toInt().toFloat(), soundLinePaint)
// c.drawLine((i / xStepSz).toFloat(), soundFFTMag[i].toInt().toFloat(), (i / xStepSz + 1).toFloat(), soundFFTMag[i + 1].toInt().toFloat(), soundLinePaint)

if ((i - 12) % 50 == 0) {
p.color = Color.BLACK
Expand All @@ -194,14 +145,11 @@ class MySurfaceView : SurfaceView, SurfaceHolder.Callback {

}


holder.unlockCanvasAndPost(c)

}
}


fun start() {
private fun start() {

executor.scheduleAtFixedRate( {
draw()
Expand All @@ -210,7 +158,7 @@ class MySurfaceView : SurfaceView, SurfaceHolder.Callback {
}


fun rand(from: Int, to: Int) : Int {
private fun rand(from: Int, to: Int) : Int {
return Random().nextInt(to-from) + from
}

Expand Down
Loading