Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cache mechanism to sherpa tts #1732

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,12 @@ class MainActivity : AppCompatActivity() {
ruleFars = ruleFars ?: "",
)!!

tts = OfflineTts(assetManager = assets, config = config)
val cacheConfig = getOfflineTtsCacheMechanismConfig(
dataDir = dataDir ?: "",
cacheSize = 20*1024*1024, // Fixed to 20 MBs
)!!

tts = OfflineTts(assetManager = assets, config = config, cacheConfig = cacheConfig)
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import androidx.compose.material3.Slider
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -46,6 +47,8 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import kotlin.math.roundToInt
import kotlinx.coroutines.delay
import kotlin.time.TimeSource

const val TAG = "sherpa-onnx-tts-engine"
Expand Down Expand Up @@ -76,6 +79,9 @@ class MainActivity : ComponentActivity() {
Log.i(TAG, "Finish initializing AudioTrack")

val preferenceHelper = PreferenceHelper(this)

TtsEngine.cacheSize = preferenceHelper.getTtsMechanismCacheSize()

setContent {
SherpaOnnxTtsEngineTheme {
// A surface container using the 'background' color from the theme
Expand All @@ -88,17 +94,44 @@ class MainActivity : ComponentActivity() {
}) {
Box(modifier = Modifier.padding(it)) {
Column(modifier = Modifier.padding(16.dp)) {
// Track used cache size in a mutable state
var usedCacheSize by remember { mutableStateOf(0) }

// LaunchedEffect to periodically update the used cache size
LaunchedEffect(Unit) {
mah92 marked this conversation as resolved.
Show resolved Hide resolved
while (true) {
usedCacheSize = TtsEngine.tts?.getTotalUsedCacheSize() ?: 0
delay(5000) // Update every 5 seconds
}
}

Column {
Text("Speed " + String.format("%.1f", TtsEngine.speed))
Slider(
value = TtsEngine.speedState.value,
onValueChange = {
TtsEngine.speed = it
preferenceHelper.setSpeed(it)
TtsEngine.tts?.clearCache() // Call the clearCache method
usedCacheSize = 0 // Reset used cache size
},
valueRange = 0.2F..3.0F,
modifier = Modifier.fillMaxWidth()
)

Text("Cache Size: ${TtsEngine.cacheSize / (1024 * 1024)}MB (${usedCacheSize / (1024 * 1024)}MB used)")
Slider(
value = TtsEngine.cacheSizeState.value.toFloat(),
onValueChange = { newValue ->
// Round the value to the nearest multiple of 5MB
val roundedValue = (newValue / (5 * 1024 * 1024)).roundToInt() * (5 * 1024 * 1024)
TtsEngine.cacheSize = roundedValue
preferenceHelper.setCacheSize(roundedValue)
TtsEngine.tts?.setCacheSize(roundedValue)
},
valueRange = 0f..209715200f, // 200MB
modifier = Modifier.fillMaxWidth()
)
}

val testTextContent = getSampleText(TtsEngine.lang ?: "")
Expand Down Expand Up @@ -272,6 +305,13 @@ class MainActivity : ComponentActivity() {
}
}

override fun onResume() {
super.onResume()
// Update used cache size when the app is resumed
val usedCacheSize = (TtsEngine.tts?.getTotalUsedCacheSize() ?: 0)
Log.i(TAG, "App resumed. Used cache size: ${usedCacheSize}B")
}

override fun onDestroy() {
stopMediaPlayer()
super.onDestroy()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class PreferenceHelper(context: Context) {
private val PREFS_NAME = "com.k2fsa.sherpa.onnx.tts.engine"
private val SPEED_KEY = "speed"
private val SID_KEY = "speaker_id"
private val CACHE_SIZE_KEY = "cache_size"

private val sharedPreferences: SharedPreferences =
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
Expand All @@ -29,4 +30,14 @@ class PreferenceHelper(context: Context) {
fun getSid(): Int {
return sharedPreferences.getInt(SID_KEY, 0)
}
}

fun setCacheSize(value: Int) {
val editor = sharedPreferences.edit()
editor.putInt(CACHE_SIZE_KEY, value)
editor.apply()
}

fun getTtsMechanismCacheSize(): Int {
return sharedPreferences.getInt(CACHE_SIZE_KEY, 20*(1024*1024)) // Default cache size is 20MB
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf
import com.k2fsa.sherpa.onnx.OfflineTts
import com.k2fsa.sherpa.onnx.getOfflineTtsConfig
import com.k2fsa.sherpa.onnx.getOfflineTtsCacheMechanismConfig
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
Expand All @@ -25,6 +26,7 @@ object TtsEngine {


val speedState: MutableState<Float> = mutableFloatStateOf(1.0F)
val cacheSizeState: MutableState<Int> = mutableIntStateOf(0)
val speakerIdState: MutableState<Int> = mutableIntStateOf(0)

var speed: Float
Expand All @@ -33,6 +35,12 @@ object TtsEngine {
speedState.value = value
}

var cacheSize: Int
get() = cacheSizeState.value
set(value) {
cacheSizeState.value = value
}

var speakerId: Int
get() = speakerIdState.value
set(value) {
Expand Down Expand Up @@ -188,10 +196,17 @@ object TtsEngine {
ruleFars = ruleFars ?: ""
)

cacheSize = PreferenceHelper(context).getTtsMechanismCacheSize()
val cacheConfig = getOfflineTtsCacheMechanismConfig(
dataDir = dataDir ?: "",
cacheSize = cacheSize,
)

speed = PreferenceHelper(context).getSpeed()
speakerId = PreferenceHelper(context).getSid()
cacheSize = PreferenceHelper(context).getCacheSizeInMB()

tts = OfflineTts(assetManager = assets, config = config)
tts = OfflineTts(assetManager = assets, config = config, cacheConfig = cacheConfig)
}


Expand Down
2 changes: 2 additions & 0 deletions sherpa-onnx/csrc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ if(SHERPA_ONNX_ENABLE_TTS)
jieba-lexicon.cc
lexicon.cc
melo-tts-lexicon.cc
offline-tts-cache-mechanism-config.cc
offline-tts-cache-mechanism.cc
offline-tts-character-frontend.cc
offline-tts-frontend.cc
offline-tts-impl.cc
Expand Down
35 changes: 35 additions & 0 deletions sherpa-onnx/csrc/offline-tts-cache-mechanism-config.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// sherpa-onnx/csrc/offline-tts-cache-mechanism-config.cc
//
// Copyright (c) 2025 @mah92 From Iranian people to the community with love

#include "sherpa-onnx/csrc/offline-tts-cache-mechanism-config.h"

#include <vector>

#include "sherpa-onnx/csrc/file-utils.h"
#include "sherpa-onnx/csrc/macros.h"

namespace sherpa_onnx {

void OfflineTtsCacheMechanismConfig::Register(ParseOptions *po) {
po->Register("tts-cache-dir", &cache_dir,
"Path to the directory containing dict for espeak-ng.");
po->Register("tts-cache-size", &cache_size,
"Cache size for wav files in bytes. After the cache size is filled, wav files are kept based on usage statstics.");
}

bool OfflineTtsCacheMechanismConfig::Validate() const {
return true;
}

std::string OfflineTtsCacheMechanismConfig::ToString() const {
std::ostringstream os;

os << "OfflineTtsCacheMechanismConfig(";
os << "cache_dir=\"" << cache_dir << "\", ";
os << "cache_size=" << cache_size << ")";

return os.str();
}

} // namespace sherpa_onnx
35 changes: 35 additions & 0 deletions sherpa-onnx/csrc/offline-tts-cache-mechanism-config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// sherpa-onnx/csrc/offline-tts-cache-mechanism-config.h
//
// Copyright (c) 2025 @mah92 From Iranian people to the community with love

#ifndef SHERPA_ONNX_CSRC_OFFLINE_TTS_CACHE_MECHANISM_CONFIG_H_
#define SHERPA_ONNX_CSRC_OFFLINE_TTS_CACHE_MECHANISM_CONFIG_H_

#include <string>

#include "sherpa-onnx/csrc/parse-options.h"

namespace sherpa_onnx {

struct OfflineTtsCacheMechanismConfig {

std::string cache_dir;

int32_t cache_size;

OfflineTtsCacheMechanismConfig() = default;

OfflineTtsCacheMechanismConfig(const std::string &cache_dir,
int32_t cache_size)
: cache_dir(cache_dir),
cache_size(cache_size) {}

void Register(ParseOptions *po);
bool Validate() const;

std::string ToString() const;
};

} // namespace sherpa_onnx

#endif // SHERPA_ONNX_CSRC_OFFLINE_TTS_CACHE_MECHANISM_CONFIG_H_
Loading