A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 273 lines 8.4 kB view raw
1/*************************************************************************** 2* __________ __ ___. 3* Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7* \/ \/ \/ \/ \/ 8* $Id$ 9* 10* Copyright (C) 2010 Thomas Martitz, Andree Buschmann 11* 12* This program is free software; you can redistribute it and/or 13* modify it under the terms of the GNU General Public License 14* as published by the Free Software Foundation; either version 2 15* of the License, or (at your option) any later version. 16* 17* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18* KIND, either express or implied. 19* 20****************************************************************************/ 21 22#include "plugin.h" 23 24#if PLUGIN_BUFFER_SIZE <= 0x8000 25#define BUF_SIZE (1<<12) /* 16 KB = (1<<12)*sizeof(int) */ 26#elif PLUGIN_BUFFER_SIZE <= 0x10000 27#define BUF_SIZE (1<<13) /* 32 KB = (1<<13)*sizeof(int) */ 28#elif PLUGIN_BUFFER_SIZE <= 0x20000 29#define BUF_SIZE (1<<14) /* 64 KB = (1<<14)*sizeof(int) */ 30#else 31#define BUF_SIZE (1<<15) /* 128 KB = (1<<15)*sizeof(int) */ 32#endif 33 34#define LOOP_REPEAT_DRAM 256 35#define MAX_REPEAT_DRAM 512 36static int loop_repeat_dram = LOOP_REPEAT_DRAM; 37static volatile int buf_dram[BUF_SIZE] MEM_ALIGN_ATTR; 38 39#if defined(PLUGIN_USE_IRAM) 40 41#if PLUGIN_BUFFER_SIZE <= 0x8000 42#define IBUF_SIZE (1<<12) /* 16 KB = (1<<12)*sizeof(int) */ 43#else 44#define IBUF_SIZE (1<<13) /* 32 KB = (1<<13)*sizeof(int) */ 45#endif 46 47#define LOOP_REPEAT_IRAM 256 48#define MAX_REPEAT_IRAM 512 49static int loop_repeat_iram = LOOP_REPEAT_DRAM; 50static volatile int buf_iram[IBUF_SIZE] IBSS_ATTR MEM_ALIGN_ATTR; 51#endif 52 53/* (Byte per loop * loops)>>20 * ticks per s * 10 / ticks = dMB per s */ 54#define dMB_PER_SEC(buf_size, cnt, delta) ((((buf_size*sizeof(int)*cnt)>>20)*HZ*10)/delta) 55 56static void memset_test(volatile int *buf, int buf_size, int loop_cnt) 57{ 58 size_t buf_bytes = buf_size*sizeof(buf[0]); 59 for(int i = 0; i < loop_cnt; i++) 60 { 61 memset((void*)buf, 0xff, buf_bytes); 62 } 63} 64 65static void memcpy_test(volatile int *buf, int buf_size, int loop_cnt) 66{ 67 /* half-size memcpy since memory regions must not overlap */ 68 void* half_buf = (void*)(&buf[buf_size/2]); 69 size_t half_buf_bytes = buf_size * sizeof(buf[0]) / 2; 70 71 /* double loop count to compensate for half size memcpy */ 72 for(int i = 0; i < loop_cnt*2; i++) 73 { 74 memcpy((void*)&buf[0], half_buf, half_buf_bytes); 75 } 76} 77 78static void write_test(volatile int *buf, int buf_size, int loop_cnt) 79{ 80#if defined(CPU_ARM) 81 asm volatile ( 82 "mov r6, %[loops] \n" 83 ".outer_loop_write: \n" 84 "mov r4, %[buf_p] \n" 85 "mov r5, %[size] \n" 86 ".inner_loop_write: \n" 87 "ldmia r4!, {r0-r3} \n" 88 "subs r5, r5, #8 \n" 89 "ldmia r4!, {r0-r3} \n" 90 "bgt .inner_loop_write \n" 91 "subs r6, r6, #1 \n" 92 "bgt .outer_loop_write \n" 93 : 94 : [loops] "r" (loop_cnt), [size] "r" (buf_size), [buf_p] "r" (buf) 95 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory", "cc" 96 ); 97#else 98 for(int i = 0; i < loop_cnt; i++) 99 { 100 for(int j = 0; j < buf_size; j+=4) 101 { 102 buf[j ] = j; 103 buf[j+1] = j+1; 104 buf[j+2] = j+2; 105 buf[j+3] = j+3; 106 } 107 } 108#endif 109} 110 111static void read_test(volatile int *buf, int buf_size, int loop_cnt) 112{ 113#if defined(CPU_ARM) 114 asm volatile ( 115 "mov r0, #0 \n" 116 "mov r1, #1 \n" 117 "mov r2, #2 \n" 118 "mov r3, #3 \n" 119 "mov r6, %[loops] \n" 120 ".outer_loop_read: \n" 121 "mov r4, %[buf_p] \n" 122 "mov r5, %[size] \n" 123 ".inner_loop_read: \n" 124 "stmia r4!, {r0-r3} \n" 125 "stmia r4!, {r0-r3} \n" 126 "subs r5, r5, #8 \n" 127 "bgt .inner_loop_read \n" 128 "subs r6, r6, #1 \n" 129 "bgt .outer_loop_read \n" 130 : 131 : [loops] "r" (loop_cnt), [size] "r" (buf_size), [buf_p] "r" (buf) 132 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory", "cc" 133 ); 134#else 135 int x, i, j; 136 for(i = 0; i < loop_cnt; i++) 137 { 138 for(j = 0; j < buf_size - 4; j+=4) 139 { 140 x = buf[j ]; 141 x = buf[j+2]; 142 x = buf[j+3]; 143 x = buf[j+4]; 144 } 145 } 146 (void)x; 147#endif 148} 149 150enum test_type { 151 READ, 152 WRITE, 153 MEMSET, 154 MEMCPY, 155}; 156 157static const char tests[][7] = { 158 [READ] = "read ", 159 [WRITE] = "write ", 160 [MEMSET] = "memset", 161 [MEMCPY] = "memcpy", 162}; 163 164static int line; 165#define TEST_MEM_PRINTF(...) rb->screens[0]->putsf(0, line++, __VA_ARGS__) 166 167static int test(volatile int *buf, int buf_size, int loop_cnt, 168 enum test_type type) 169{ 170 int delta, dMB; 171 int last_tick = *rb->current_tick; 172 int ret = 0; 173 174 switch(type) 175 { 176 case READ: read_test(buf, buf_size, loop_cnt); break; 177 case WRITE: write_test(buf, buf_size, loop_cnt); break; 178 case MEMSET: memset_test(buf, buf_size, loop_cnt); break; 179 case MEMCPY: memcpy_test(buf, buf_size, loop_cnt); break; 180 } 181 182 delta = *rb->current_tick - last_tick; 183 184 if (delta <= 20) 185 { 186 /* The loop_cnt will be increased for the next measurement set until 187 * each measurement at least takes 10 ticks. This is to ensure a 188 * minimum accuracy. */ 189 ret = 1; 190 } 191 192 delta = delta>0 ? delta : delta+1; 193 dMB = dMB_PER_SEC(buf_size, loop_cnt, delta); 194 TEST_MEM_PRINTF("%s: %3d.%d MB/s (%3d ms)", 195 tests[type], dMB/10, dMB%10, delta*10); 196 197 return ret; 198} 199 200enum plugin_status plugin_start(const void* parameter) 201{ 202 (void)parameter; 203 bool done = false; 204#ifdef HAVE_ADJUSTABLE_CPU_FREQ 205 bool boost = false; 206#endif 207 int count = 0; 208 209 rb->lcd_setfont(FONT_SYSFIXED); 210 211 rb->screens[0]->clear_display(); 212 TEST_MEM_PRINTF("patience, may take some seconds..."); 213 rb->screens[0]->update(); 214 215 while (!done) 216 { 217 line = 0; 218 int ret; 219 rb->screens[0]->clear_display(); 220#ifdef HAVE_ADJUSTABLE_CPU_FREQ 221 TEST_MEM_PRINTF("%s", boost?"boosted":"unboosted"); 222 TEST_MEM_PRINTF("clock: %3d.%d MHz", (*rb->cpu_frequency)/1000000, (*rb->cpu_frequency)%1000000); 223#endif 224 TEST_MEM_PRINTF("loop#: %d", ++count); 225 226 TEST_MEM_PRINTF("DRAM cnt: %d size: %d MB", loop_repeat_dram, 227 (loop_repeat_dram*BUF_SIZE*sizeof(buf_dram[0]))>>20); 228 ret = 0; 229 ret |= test(buf_dram, BUF_SIZE, loop_repeat_dram, READ); 230 ret |= test(buf_dram, BUF_SIZE, loop_repeat_dram, WRITE); 231 ret |= test(buf_dram, BUF_SIZE, loop_repeat_dram, MEMSET); 232 ret |= test(buf_dram, BUF_SIZE, loop_repeat_dram, MEMCPY); 233 if (ret != 0 && loop_repeat_dram < MAX_REPEAT_DRAM) loop_repeat_dram *= 2; 234#if defined(PLUGIN_USE_IRAM) 235 TEST_MEM_PRINTF("IRAM cnt: %d size: %d MB", loop_repeat_iram, 236 (loop_repeat_iram*BUF_SIZE*sizeof(buf_iram[0]))>>20); 237 ret = 0; 238 ret |= test(buf_iram, BUF_SIZE, loop_repeat_iram, READ); 239 ret |= test(buf_iram, BUF_SIZE, loop_repeat_iram, WRITE); 240 ret |= test(buf_iram, BUF_SIZE, loop_repeat_iram, MEMSET); 241 ret |= test(buf_iram, BUF_SIZE, loop_repeat_iram, MEMCPY); 242 if (ret != 0 && loop_repeat_iram < MAX_REPEAT_IRAM) loop_repeat_iram *= 2; 243#endif 244 245 rb->screens[0]->update(); 246 247 switch (rb->get_action(CONTEXT_STD, HZ/5)) 248 { 249#ifdef HAVE_ADJUSTABLE_CPU_FREQ 250 case ACTION_STD_PREV: 251 if (!boost) 252 { 253 rb->cpu_boost(true); 254 boost = true; 255 } 256 break; 257 258 case ACTION_STD_NEXT: 259 if (boost) 260 { 261 rb->cpu_boost(false); 262 boost = false; 263 } 264 break; 265#endif 266 case ACTION_STD_CANCEL: 267 done = true; 268 break; 269 } 270 } 271 272 return PLUGIN_OK; 273}