Skip to content

Commit

Permalink
feat: Add offline resampler for IRS files
Browse files Browse the repository at this point in the history
  • Loading branch information
timschneeb committed Oct 24, 2022
1 parent ea364c9 commit 91eb49b
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package me.timschneeberger.rootlessjamesdsp

import android.app.Application
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.*
import android.media.audiofx.AudioEffect
import android.os.Build
import android.util.Log
Expand All @@ -24,6 +22,7 @@ import me.timschneeberger.rootlessjamesdsp.BuildConfig
import me.timschneeberger.rootlessjamesdsp.R
import me.timschneeberger.rootlessjamesdsp.service.RootAudioProcessorService
import me.timschneeberger.rootlessjamesdsp.session.root.EffectSessionManager
import me.timschneeberger.rootlessjamesdsp.utils.ContextExtensions.registerLocalReceiver
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.GlobalContext.startKoin
Expand Down Expand Up @@ -51,6 +50,19 @@ class MainApplication : Application(), SharedPreferences.OnSharedPreferenceChang
val blockedAppDatabase by lazy { AppBlocklistDatabase.getDatabase(this, applicationScope) }
val blockedAppRepository by lazy { AppBlocklistRepository(blockedAppDatabase.appBlocklistDao()) }

var engineSampleRate = 0f
private set

private val receiver by lazy {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == Constants.ACTION_REPORT_SAMPLE_RATE) {
engineSampleRate = intent.getFloatExtra(Constants.EXTRA_SAMPLE_RATE, 0f)
}
}
}
}

override fun onCreate() {
Timber.plant(DebugTree())
Timber.plant(CrashReportingTree())
Expand Down Expand Up @@ -103,6 +115,8 @@ class MainApplication : Application(), SharedPreferences.OnSharedPreferenceChang
modules(appModule)
}

registerLocalReceiver(receiver, IntentFilter(Constants.ACTION_REPORT_SAMPLE_RATE))

if (!BuildConfig.ROOTLESS && isLegacyMode)
RootAudioProcessorService.updateLegacyMode(applicationContext, true)

Expand All @@ -111,6 +125,7 @@ class MainApplication : Application(), SharedPreferences.OnSharedPreferenceChang

override fun onTerminate() {
prefs.unregisterOnSharedPreferenceChangeListener(this)
unregisterReceiver(receiver)
super.onTerminate()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.media.AudioManager
import android.os.Bundle
import android.os.Handler
import android.os.Looper
Expand All @@ -18,14 +19,18 @@ import androidx.core.view.isVisible
import androidx.preference.ListPreferenceDialogFragmentCompat
import kotlinx.coroutines.*
import me.timschneeberger.rootlessjamesdsp.BuildConfig
import me.timschneeberger.rootlessjamesdsp.MainApplication
import me.timschneeberger.rootlessjamesdsp.R
import me.timschneeberger.rootlessjamesdsp.interop.JdspImpResToolbox
import me.timschneeberger.rootlessjamesdsp.model.Preset
import me.timschneeberger.rootlessjamesdsp.preference.FileLibraryPreference
import me.timschneeberger.rootlessjamesdsp.utils.ContextExtensions.showAlert
import me.timschneeberger.rootlessjamesdsp.utils.ContextExtensions.showInputAlert
import me.timschneeberger.rootlessjamesdsp.utils.StorageUtils
import me.timschneeberger.rootlessjamesdsp.utils.SystemServices
import timber.log.Timber
import java.io.File
import kotlin.math.roundToInt


class FileLibraryDialogFragment : ListPreferenceDialogFragmentCompat() {
Expand Down Expand Up @@ -89,10 +94,41 @@ class FileLibraryDialogFragment : ListPreferenceDialogFragmentCompat() {
popupMenu.menu.findItem(R.id.duplicate_selection).isVisible =
fileLibPreference.isLiveprog() || fileLibPreference.isPreset()
popupMenu.menu.findItem(R.id.overwrite_selection).isVisible = fileLibPreference.isPreset()
popupMenu.menu.findItem(R.id.resample_selection).isVisible = fileLibPreference.isIrs()

popupMenu.setOnMenuItemClickListener { menuItem ->
val selectedFile = File(path.toString())
when (menuItem.itemId) {
R.id.resample_selection -> {
if(fileLibPreference.isIrs()) {
var targetRate = (requireActivity().application as MainApplication).engineSampleRate.roundToInt()
if (targetRate <= 0) {
targetRate = SystemServices.get(requireContext(), AudioManager::class.java)
.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)
?.let { str -> Integer.parseInt(str).takeUnless { it == 0 } } ?: 48000
Timber.w("resample: engine sample rate is zero, using HAL rate instead")
}

Timber.d("resample: Resampling ${selectedFile.name} to ${targetRate}Hz")

CoroutineScope(Dispatchers.IO).launch {
val newName = JdspImpResToolbox.OfflineAudioResample(
(selectedFile.absoluteFile.parentFile?.absolutePath + "/") ?: "",
selectedFile.name,
targetRate
)

withContext(Dispatchers.Main) {
if (newName == "Invalid")
showMessage(getString(R.string.filelibrary_resample_failed))
else
showMessage(getString(R.string.filelibrary_resample_complete, targetRate))
refresh()
}
}
}
refresh()
}
R.id.overwrite_selection -> {
if(fileLibPreference.isPreset()) {
Preset(selectedFile.name).save()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package me.timschneeberger.rootlessjamesdsp.interop

import android.content.Context
import android.content.Intent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
Expand All @@ -10,21 +11,27 @@ import kotlinx.coroutines.sync.withLock
import me.timschneeberger.rootlessjamesdsp.R
import me.timschneeberger.rootlessjamesdsp.utils.Constants
import me.timschneeberger.rootlessjamesdsp.interop.structure.EelVmVariable
import me.timschneeberger.rootlessjamesdsp.utils.ContextExtensions.sendLocalBroadcast
import timber.log.Timber
import java.io.File
import java.io.FileReader
import java.lang.NumberFormatException

abstract class JamesDspBaseEngine(val context: Context, val callbacks: JamesDspWrapper.JamesDspCallbacks? = null) : AutoCloseable {
abstract var enabled: Boolean
abstract var sampleRate: Float
open var sampleRate: Float = 0.0f
set(value) {
field = value
reportSampleRate(value)
}

private val syncScope = CoroutineScope(Dispatchers.IO)
private val syncMutex = Mutex()
protected val cache = PreferenceCache(context)

override fun close() {
Timber.d("Closing engine")
reportSampleRate(0f)
syncScope.cancel()
}

Expand All @@ -38,6 +45,12 @@ abstract class JamesDspBaseEngine(val context: Context, val callbacks: JamesDspW
cache.clear()
}

private fun reportSampleRate(value: Float) {
context.sendLocalBroadcast(Intent(Constants.ACTION_REPORT_SAMPLE_RATE).apply {
putExtra(Constants.EXTRA_SAMPLE_RATE, value)
})
}

private suspend fun syncWithPreferencesAsync(forceUpdateNamespaces: Array<String>? = null) {
Timber.d("Synchronizing with preferences... (forced: %s)", forceUpdateNamespaces?.joinToString(";") { it })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import timber.log.Timber
class JamesDspLocalEngine(context: Context, callbacks: JamesDspWrapper.JamesDspCallbacks? = null) : JamesDspBaseEngine(context, callbacks) {
var handle: JamesDspHandle = JamesDspWrapper.alloc(callbacks ?: DummyCallbacks())

override var sampleRate: Float = 48000.0f
override var sampleRate: Float
set(value) {
field = value
super.sampleRate = value
JamesDspWrapper.setSamplingRate(handle, value, false)
}
get() = super.sampleRate
override var enabled: Boolean = true

override fun close() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ class JamesDspRemoteEngine(
get() = effect.enabled

override var sampleRate: Float
get() = effect.getParameterInt(20001)?.toFloat() ?: -0f
get() {
super.sampleRate = effect.getParameterInt(20001)?.toFloat() ?: -0f
return super.sampleRate
}
set(_){}

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ object JdspImpResToolbox {
): FloatArray?

external fun OfflineAudioResample(
path: String?,
filename: String?,
path: String,
filename: String,
targetSampleRate: Int
): String?
): String

external fun ComputeEqResponse(
n: Int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ object Constants {
const val ACTION_SERVICE_SOFT_REBOOT_CORE = BuildConfig.APPLICATION_ID + ".action.service.SOFT_REBOOT_CORE"
const val ACTION_PROCESSOR_MESSAGE = BuildConfig.APPLICATION_ID + ".action.service.PROCESSOR_MESSAGE"
const val ACTION_DISCARD_AUTHORIZATION = BuildConfig.APPLICATION_ID + ".action.service.DISCARD_AUTHORIZATION"
const val ACTION_REPORT_SAMPLE_RATE = BuildConfig.APPLICATION_ID + ".action.service.REPORT_SAMPLE_RATE"

// Intent extras
const val EXTRA_SAMPLE_RATE = BuildConfig.APPLICATION_ID + ".extra.service.SAMPLE_RATE"

// Notifications
const val CHANNEL_ID_SERVICE = "JamesDSP"
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/menu/menu_filelibrary_context.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
android:id="@+id/duplicate_selection"
android:title="@string/filelibrary_context_duplicate" />

<item
android:id="@+id/resample_selection"
android:title="@string/filelibrary_context_resample" />

<item
android:id="@+id/share_selection"
android:title="@string/filelibrary_context_share" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@
<string name="filelibrary_context_overwrite">Overwrite</string>
<string name="filelibrary_context_rename">Rename</string>
<string name="filelibrary_context_share">Share…</string>
<string name="filelibrary_context_resample">Offline resample</string>
<string name="filelibrary_context_duplicate">Duplicate</string>
<string name="filelibrary_context_delete">Delete</string>
<string name="filelibrary_context_new_preset">New</string>
Expand All @@ -337,6 +338,8 @@
<string name="filelibrary_no_file_selected">No file selected</string>
<string name="filelibrary_new_file_name">New file name</string>
<string name="filelibrary_file_exists">File exists already</string>
<string name="filelibrary_resample_complete">Resampled to %1$dHz</string>
<string name="filelibrary_resample_failed">Resampling failed. Corrupt input file?</string>
<string name="filelibrary_preset_overwritten">Preset \'%1$s\' overwritten</string>
<string name="filelibrary_preset_created">Preset \'%1$s\' created</string>
<string name="filelibrary_renamed">Renamed to \'%1$s\'</string>
Expand Down

0 comments on commit 91eb49b

Please sign in to comment.