Skip to content

Instantly share code, notes, and snippets.

@YohannesTz
Created September 1, 2023 15:58
Show Gist options
  • Save YohannesTz/a1f2f23b59073ac47fb808b3b28b764f to your computer and use it in GitHub Desktop.
Save YohannesTz/a1f2f23b59073ac47fb808b3b28b764f to your computer and use it in GitHub Desktop.
Audio With Freq Generator
package com.github.yohannestz.streofreq
import android.content.Context
import android.media.AudioAttributes
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioTrack
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.github.yohannestz.streofreq.ui.theme.StreoFreqTheme
import kotlin.math.sin
class MainActivity : ComponentActivity() {
private lateinit var leftAudioTrack: AudioTrack
private lateinit var rightAudioTrack: AudioTrack
private val sampleRate = 44100 // Adjust as per your requirements
private var bufferSize = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
StreoFreqTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
}
}
}
val audioAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
val leftAudioFormat = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) {
AudioFormat.Builder()
.setSampleRate(sampleRate)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_SIDE_LEFT)
.build()
} else {
AudioFormat.Builder()
.setSampleRate(sampleRate)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.build()
}
val rightAudioFormat = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) {
AudioFormat.Builder()
.setSampleRate(sampleRate)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_SIDE_RIGHT)
.build()
} else {
AudioFormat.Builder()
.setSampleRate(sampleRate)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.build()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.e("Count: ", rightAudioFormat.channelCount.toString())
}
this.bufferSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT)
leftAudioTrack = AudioTrack(audioAttributes, leftAudioFormat, bufferSize, AudioTrack.MODE_STREAM, 0)
rightAudioTrack = AudioTrack(audioAttributes, rightAudioFormat, bufferSize, AudioTrack.MODE_STREAM, 0)
}
override fun onResume() {
super.onResume()
leftAudioTrack.play()
rightAudioTrack.play()
val frequencyLeft = 148.0 // Adjust as per your requirements
val frequencyRight = 800.0 // Adjust as per your requirements
val durationSeconds = 5.0 // Adjust as per your requirements
val numSamples = (sampleRate * durationSeconds / 1000).toInt()
val buffer = ShortArray(numSamples)
val rightBuffer = ShortArray(numSamples)
Log.e("bufferSize", "bufferSize: ${buffer.size}")
Log.e("numsamples", "numSample: $numSamples")
Thread {
while (!Thread.currentThread().isInterrupted) {
/*for (i in 0 until bufferSize - 1) {
val time = (i / sampleRate.toDouble()) % durationSeconds
buffer[i] = (sin(2 * Math.PI * frequencyLeft * time) * Short.MAX_VALUE).toInt().toShort()
}
leftAudioTrack.write(buffer, 0, bufferSize)
for (i in 0 until bufferSize) {
val time = (i / sampleRate.toDouble()) % durationSeconds
rightBuffer[i] = (sin(2 * Math.PI * frequencyRight * time) * Short.MAX_VALUE).toInt().toShort()
}
rightAudioTrack.write(rightBuffer, 0, bufferSize)*/
/*for (sampleIndex in 0 until numSamples) {
//val sampleLeft = (sin(2 * Math.PI * frequencyLeft * time) * Short.MAX_VALUE).toInt().toShort()
// Calculate the sample value for the right channel
//val sampleRight = (sin(2 * Math.PI * frequencyRight * time) * Short.MAX_VALUE).toInt().toShort()
val sampleLeft = (sin(leftAngle) * Short.MAX_VALUE).toInt().toShort()
val sampleRight = (sin(rightAngle) * Short.MAX_VALUE).toInt().toShort()
// Set the samples in the audio buffer
//buffer[sampleIndex % bufferSize] = sampleLeft // Left channel
//buffer[(sampleIndex % bufferSize) + 1] = sampleRight // Right channel
//Log.e("sampleIndex: ", "$sampleIndex")
buffer[sampleIndex] = sampleLeft
rightBuffer[sampleIndex] = sampleRight
leftAngle += leftAngleDelta
rightAngle += rightAngleDelta
}
leftAudioTrack.write(buffer, 0, bufferSize)
rightAudioTrack.write(rightBuffer, 0, bufferSize)*/
val leftAngleDelta = 2.0 * Math.PI * frequencyLeft / sampleRate
val rightAngleDelta = 2.0 * Math.PI * frequencyRight / sampleRate
var leftAngle = 0.0
var rightAngle = 0.0
for (i in 0 until numSamples) {
val leftSample = (sin(leftAngle) * Short.MAX_VALUE).toInt().toShort()
val rightSample = (sin(rightAngle) * Short.MAX_VALUE).toInt().toShort()
//buffer[i] = (leftSample + rightSample).toShort()
buffer[i] = leftSample
rightBuffer[i] = rightSample
leftAngle += leftAngleDelta
rightAngle += rightAngleDelta
}
leftAudioTrack.write(buffer, 0, buffer.size)
rightAudioTrack.write(rightBuffer, 0, rightBuffer.size)
}
}.start()
}
override fun onPause() {
super.onPause()
leftAudioTrack.stop()
leftAudioTrack.release()
rightAudioTrack.stop()
rightAudioTrack.release()
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment