Skip to content

Commit

Permalink
Preload samples for quicker startup
Browse files Browse the repository at this point in the history
  • Loading branch information
thetwom committed Jul 28, 2022
1 parent 740fd0f commit bab7c81
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 3 deletions.
26 changes: 25 additions & 1 deletion app/src/main/java/de/moekadu/metronome/audio/AudioMixer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.util.Log
import de.moekadu.metronome.metronomeproperties.*
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
Expand Down Expand Up @@ -367,6 +368,17 @@ private fun computeNoteDelayInMillis(noteStartedMessages: ArrayList<NoteStartedM
*/
class AudioMixer (val context: Context, private val scope: CoroutineScope) {

private val noteSamplesForDifferentSampleRates = mapOf (
44100 to lazy {
// Log.v("Metronome", "AudioMixer: load samples for 44100Hz")
createNoteSamples(context, 44100)
},
48000 to lazy {
// Log.v("Metronome", "AudioMixer: load samples for 48000Hz")
createNoteSamples(context, 48000)
}
)

/// Note list with tracks which are played in a loop
var noteList = ArrayList<NoteListItem>()
set(value) {
Expand Down Expand Up @@ -418,6 +430,18 @@ class AudioMixer (val context: Context, private val scope: CoroutineScope) {
private val isMuteChannel = Channel<Boolean>(Channel.CONFLATED)
private var isMute: Boolean = false

init {
// preload all samples for quicker player start
scope.launch(Dispatchers.Main) {
// first load with known native sample rate, then load for all sample rates
val nativeSampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC)
noteSamplesForDifferentSampleRates[nativeSampleRate]?.value

for (n in noteSamplesForDifferentSampleRates)
n.value.value
}
}

/// Create a new NoteStartedChannel.
/**
* @warning When this is not needed anymore, you MUST call unregisterNoteStartedChannel
Expand Down Expand Up @@ -479,7 +503,7 @@ class AudioMixer (val context: Context, private val scope: CoroutineScope) {
job = scope.launch(Dispatchers.Default) {

val player = createPlayer()
val noteSamples = createNoteSamples(context, player.sampleRate)
val noteSamples = noteSamplesForDifferentSampleRates[player.sampleRate]!!.value //createNoteSamples(context, player.sampleRate)

val queuedNotes = ArrayList<QueuedNote>(32)
val queuedNoteStartedChannels = ArrayList<NoteStartedMessagingAndFrame>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package de.moekadu.metronome.fragments
import android.annotation.SuppressLint
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.os.Bundle
import android.util.Log
import android.view.*
import android.widget.ImageButton
import android.widget.TextView
Expand Down Expand Up @@ -203,7 +204,7 @@ class MetronomeFragment : Fragment() {
}

override fun onPlay() {
// Log.v("Metronome", "playButton:onPause()")
Log.v("Metronome", "MetronomeFragment: playButton:onPlay()")
viewModel.play()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import android.os.Binder
import android.os.IBinder
import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat
import android.util.Log
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
Expand Down Expand Up @@ -291,20 +292,23 @@ class PlayerService : LifecycleService() {
}

fun startPlay() {
// Log.v("Metronome", "PlayerService:startPlay")
// Log.v("Metronome", "PlayerService:startPlay : setting playbackState")
playbackState = playbackStateBuilder.setState(
PlaybackStateCompat.STATE_PLAYING,
PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN,
bpm.bpm
).build()
mediaSession?.setPlaybackState(playbackState)

// Log.v("Metronome", "PlayerService:startPlay : setting notification")
notification?.state = state
notification?.let {
startForeground(PlayerNotification.id, it.notification)
}

// Log.v("Metronome", "PlayerService:startPlay : starting mixer")
audioMixer?.start()
// Log.v("Metronome", "PlayerService:startPlay : run statusChangedListeners")
statusChangedListeners.forEach { s -> s.onPlay() }
}

Expand Down

0 comments on commit bab7c81

Please sign in to comment.