Я разрабатываю аудио-приложение BLE в реальном времени на Android. Скорость выборки аудио составляет 16 000 образцов в секунду, и я получаю данные в 100 пакетах в секунду, каждый пакет имеет 160 образцов (так что ровно 16 кГц). < /P>
Для визуализации я понижаю данные от 16 кГц до 500 Гц и настройте его с помощью Linechart MpandroidChart. Диаграмма настроена на: < /p>
static (не разбрызгиваемое) < /p>
Фиксированная ширина просмотра < /p>
Повторное использование объектов ввода для оптимизации производительности < /p>
показывает «пробел курсора», чтобы указать актуальную обновленную позицию. Позиция обновления достигает конца видимого видоубийта, график графиков - она либо прыгает, мерцает, либо кратко показывает противоречивые значения. < /p>
Вот код (я сделал демо -версию, моделируя аудиоданные с помощью цикла): < /p>
@Composable
fun LiveWaveformChart(
modifier: Modifier = Modifier,
visibleEntries: Int = 2000
) {
val context = LocalContext.current
val chart = remember { LineChart(context) }
val cursorPosition = remember { mutableIntStateOf(0) }
val entriesBuffer = remember { mutableStateListOf() }
val gapSize = remember { (visibleEntries * 0.02).toInt().coerceAtLeast(5) }
val cursorOffset = remember { (visibleEntries * 0.9975).toInt() }
LaunchedEffect(visibleEntries) {
entriesBuffer.clear()
entriesBuffer.addAll(List(visibleEntries) { Entry(it.toFloat(), 0f) })
setupChart(chart, visibleEntries)
}
DisposableEffect(Unit) {
onDispose {
dataPointer = 0
}
}
AndroidView(
factory = { chart },
modifier = modifier.fillMaxSize()
)
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (true) {
delay(10)
val audioData = ShortArray(5) { Random.nextInt(-1000, 1000).toShort() }
withContext(Dispatchers.Main) {
plotAudio(
chart = chart,
audio = audioData,
entriesBuffer = entriesBuffer,
cursorPosition = cursorPosition,
visibleEntries = visibleEntries,
gapSize = gapSize
)
}
}
}
}
}
private fun setupChart(chart: LineChart, visibleEntries: Int) {
chart.doOnLayout {
val xGridLines = it.width / 60
val yGridLines = it.height / 60
applyDynamicGrid(chart, xGridLines, yGridLines)
}
chart.apply {
description.isEnabled = false
setTouchEnabled(false)
isDragEnabled = false
setScaleEnabled(false)
setBackgroundColor(Color.WHITE)
isAutoScaleMinMaxEnabled = true
axisRight.isEnabled = false
legend.isEnabled = false
setHardwareAccelerationEnabled(true)
setViewPortOffsets(0f, 0f, 0f, 0f)
setMaxVisibleValueCount(visibleEntries)
data = LineData().apply {
setDrawValues(false)
}
}
}
private var dataPointer = 0
fun plotAudio(
chart: LineChart,
audio: ShortArray,
entriesBuffer: MutableList,
cursorPosition: MutableState,
visibleEntries: Int,
gapSize: Int
) {
for (i in audio.indices) {
if (dataPointer >= visibleEntries) dataPointer = 0
entriesBuffer[dataPointer].y = audio.toFloat()
dataPointer++
}
cursorPosition.value = (dataPointer) % visibleEntries
val gapStart = cursorPosition.value
val gapEnd = (cursorPosition.value + gapSize) % visibleEntries
val (entriesBeforeGap, entriesAfterGap) = calculateGapEntries(
entriesBuffer,
visibleEntries,
gapStart,
gapEnd
)
val dataSet1 = createLineDataSet(entriesBeforeGap, "BeforeGap")
val dataSet2 = createLineDataSet(entriesAfterGap, "AfterGap")
chart.data?.clearValues()
chart.data?.addDataSet(dataSet1)
chart.data?.addDataSet(dataSet2)
chart.data?.notifyDataChanged()
chart.notifyDataSetChanged()
chart.setVisibleXRangeMaximum(visibleEntries.toFloat())
chart.moveViewToX(dataPointer.toFloat())
chart.invalidate()
}
private fun calculateGapEntries(
buffer: List,
visibleEntries: Int,
gapStart: Int,
gapEnd: Int
): Pair {
return if (gapStart < gapEnd) {
buffer.subList(0, gapStart) to buffer.subList(gapEnd, visibleEntries)
} else {
val before = buffer.subList(gapEnd, gapStart)
val after = buffer.subList(0, gapEnd) + buffer.subList(gapStart, visibleEntries)
before to after
}
}
private fun createLineDataSet(entries: List, label: String): LineDataSet {
return LineDataSet(entries, label).apply {
mode = LineDataSet.Mode.LINEAR
setDrawCircles(false)
setDrawValues(false)
color = Color.RED
lineWidth = 1f
}
}
private fun applyDynamicGrid(chart: LineChart, xGridLines: Int, yGridLines: Int) {
chart.xAxis.apply {
setDrawLabels(false)
setDrawGridLines(true)
setDrawAxisLine(false)
labelCount = xGridLines
granularity = 1f
isGranularityEnabled = true
gridColor = Color.LTGRAY
gridLineWidth = 0.4f
}
chart.axisLeft.apply {
setDrawLabels(false)
setDrawGridLines(true)
setDrawAxisLine(false)
axisMinimum = -32768f
axisMaximum = 32767f
labelCount = yGridLines
granularity = (axisMaximum - axisMinimum) / yGridLines
isGranularityEnabled = true
gridColor = Color.LTGRAY
gridLineWidth = 0.4f
}
}
< /code>
Как правильно реализовать плавный курсор или зазор в непротягивающейся некручивающейся в реальном времени MpandroidChart, не вызывая глюки или мерцающие, когда текущий индекс оборачивается вокруг ширины диаграммы? Проблема заключается в той части, в которой диаграмма пытается нарисовать линию, чтобы соединить последнюю точку и первую точку (например, если она рисует на индексе 1999 года, а затем вернется к 0 -й индекс, он пытается подключить обе точки в 1999 -м индексе и 0 -й индекс.>
Подробнее здесь: https://stackoverflow.com/questions/797 ... c-viewport
MpandroidChart в реальном времени сглаживание сюжета при обновлении записей со статическим просмотром и живым курсором ⇐ Android
Форум для тех, кто программирует под Android
1753938385
Anonymous
Я разрабатываю аудио-приложение BLE в реальном времени на Android. Скорость выборки аудио составляет 16 000 образцов в секунду, и я получаю данные в 100 пакетах в секунду, каждый пакет имеет 160 образцов (так что ровно 16 кГц). < /P>
Для визуализации я понижаю данные от 16 кГц до 500 Гц и настройте его с помощью Linechart MpandroidChart. Диаграмма настроена на: < /p>
static (не разбрызгиваемое) < /p>
Фиксированная ширина просмотра < /p>
Повторное использование объектов ввода для оптимизации производительности < /p>
показывает «пробел курсора», чтобы указать актуальную обновленную позицию. Позиция обновления достигает конца видимого видоубийта, график графиков - она либо прыгает, мерцает, либо кратко показывает противоречивые значения. < /p>
Вот код (я сделал демо -версию, моделируя аудиоданные с помощью цикла): < /p>
@Composable
fun LiveWaveformChart(
modifier: Modifier = Modifier,
visibleEntries: Int = 2000
) {
val context = LocalContext.current
val chart = remember { LineChart(context) }
val cursorPosition = remember { mutableIntStateOf(0) }
val entriesBuffer = remember { mutableStateListOf() }
val gapSize = remember { (visibleEntries * 0.02).toInt().coerceAtLeast(5) }
val cursorOffset = remember { (visibleEntries * 0.9975).toInt() }
LaunchedEffect(visibleEntries) {
entriesBuffer.clear()
entriesBuffer.addAll(List(visibleEntries) { Entry(it.toFloat(), 0f) })
setupChart(chart, visibleEntries)
}
DisposableEffect(Unit) {
onDispose {
dataPointer = 0
}
}
AndroidView(
factory = { chart },
modifier = modifier.fillMaxSize()
)
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (true) {
delay(10)
val audioData = ShortArray(5) { Random.nextInt(-1000, 1000).toShort() }
withContext(Dispatchers.Main) {
plotAudio(
chart = chart,
audio = audioData,
entriesBuffer = entriesBuffer,
cursorPosition = cursorPosition,
visibleEntries = visibleEntries,
gapSize = gapSize
)
}
}
}
}
}
private fun setupChart(chart: LineChart, visibleEntries: Int) {
chart.doOnLayout {
val xGridLines = it.width / 60
val yGridLines = it.height / 60
applyDynamicGrid(chart, xGridLines, yGridLines)
}
chart.apply {
description.isEnabled = false
setTouchEnabled(false)
isDragEnabled = false
setScaleEnabled(false)
setBackgroundColor(Color.WHITE)
isAutoScaleMinMaxEnabled = true
axisRight.isEnabled = false
legend.isEnabled = false
setHardwareAccelerationEnabled(true)
setViewPortOffsets(0f, 0f, 0f, 0f)
setMaxVisibleValueCount(visibleEntries)
data = LineData().apply {
setDrawValues(false)
}
}
}
private var dataPointer = 0
fun plotAudio(
chart: LineChart,
audio: ShortArray,
entriesBuffer: MutableList,
cursorPosition: MutableState,
visibleEntries: Int,
gapSize: Int
) {
for (i in audio.indices) {
if (dataPointer >= visibleEntries) dataPointer = 0
entriesBuffer[dataPointer].y = audio[i].toFloat()
dataPointer++
}
cursorPosition.value = (dataPointer) % visibleEntries
val gapStart = cursorPosition.value
val gapEnd = (cursorPosition.value + gapSize) % visibleEntries
val (entriesBeforeGap, entriesAfterGap) = calculateGapEntries(
entriesBuffer,
visibleEntries,
gapStart,
gapEnd
)
val dataSet1 = createLineDataSet(entriesBeforeGap, "BeforeGap")
val dataSet2 = createLineDataSet(entriesAfterGap, "AfterGap")
chart.data?.clearValues()
chart.data?.addDataSet(dataSet1)
chart.data?.addDataSet(dataSet2)
chart.data?.notifyDataChanged()
chart.notifyDataSetChanged()
chart.setVisibleXRangeMaximum(visibleEntries.toFloat())
chart.moveViewToX(dataPointer.toFloat())
chart.invalidate()
}
private fun calculateGapEntries(
buffer: List,
visibleEntries: Int,
gapStart: Int,
gapEnd: Int
): Pair {
return if (gapStart < gapEnd) {
buffer.subList(0, gapStart) to buffer.subList(gapEnd, visibleEntries)
} else {
val before = buffer.subList(gapEnd, gapStart)
val after = buffer.subList(0, gapEnd) + buffer.subList(gapStart, visibleEntries)
before to after
}
}
private fun createLineDataSet(entries: List, label: String): LineDataSet {
return LineDataSet(entries, label).apply {
mode = LineDataSet.Mode.LINEAR
setDrawCircles(false)
setDrawValues(false)
color = Color.RED
lineWidth = 1f
}
}
private fun applyDynamicGrid(chart: LineChart, xGridLines: Int, yGridLines: Int) {
chart.xAxis.apply {
setDrawLabels(false)
setDrawGridLines(true)
setDrawAxisLine(false)
labelCount = xGridLines
granularity = 1f
isGranularityEnabled = true
gridColor = Color.LTGRAY
gridLineWidth = 0.4f
}
chart.axisLeft.apply {
setDrawLabels(false)
setDrawGridLines(true)
setDrawAxisLine(false)
axisMinimum = -32768f
axisMaximum = 32767f
labelCount = yGridLines
granularity = (axisMaximum - axisMinimum) / yGridLines
isGranularityEnabled = true
gridColor = Color.LTGRAY
gridLineWidth = 0.4f
}
}
< /code>
Как правильно реализовать плавный курсор или зазор в непротягивающейся некручивающейся в реальном времени MpandroidChart, не вызывая глюки или мерцающие, когда текущий индекс оборачивается вокруг ширины диаграммы? Проблема заключается в той части, в которой диаграмма пытается нарисовать линию, чтобы соединить последнюю точку и первую точку (например, если она рисует на индексе 1999 года, а затем вернется к 0 -й индекс, он пытается подключить обе точки в 1999 -м индексе и 0 -й индекс.>
Подробнее здесь: [url]https://stackoverflow.com/questions/79720743/mpandroidchart-real-time-plot-glitch-when-updating-entries-with-static-viewport[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия