/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2004 Matthias Wientapper, 2014-2015 Thomas Orgis * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * TODO: * - Think about generating the sounds on startup with SWCODEC. ****************************************************************************/ #include "plugin.h" #include "lib/pluginlib_actions.h" #include "lib/pluginlib_exit.h" #include "fixedpoint.h" /* About time resolution: 1000 means 1 ms resolution. It should get better with higher values in theory, but in practice, too small timer intervals increase the chance of being missed and make the metronome lag behind. Mean tempo still works out with very small divider values (29 even) as long as the rounding error compensation is active, although beat intervals become jerky. You compromise between long-term accuracy and steadyness from one beat to the next. A drift you have to accept comes just from the audio clock itself, or even from the difference between clocks in the device. The Sansa Clip+ has around 0.04 % error in audio frequency using the "good" PLLB. I presume that the difference between timing using PLLA and PLLB is at least that big. Something up to 40 ms time difference over one minute when comparing to an external reference or just the metronome plugin with playback of a prepared PCM track is to be expected. Also, since playback on SWCODEC is not allowed to happen inside the timer callback, there is a delay introduced by the main loop scheduling. This could be compensated for by delaying the audio depending on a counter incremented since the period elapsed in the callback, at the price of putting the display out of sync. On a Clip+, the schedule delay isn't biggest problem (drift for fine timer resolution is). All in all, 1 ms is too small, 2 ms seems to work fine ... 4 ms might still be cool, too. */ #if defined(SIMULATOR) /* Simulator really wants 1024. Not 1000, not 512, only 1024. Otherwise it is strangely slow. */ static const unsigned int timerfreq_div = 1024; #else static const unsigned int timerfreq_div = 500; /* 2 ms resolution */ #endif /* actual (not quarter) beats per minute above which display blinking is deactivated (since it is not needed anymore and because of performance issues) */ static const unsigned int blinklimit = 135; enum metronome_errors { MERR_NOTHING = 0 , MERR_MISSING , MERR_OOM , MERR_TEMPO , MERR_METER , MERR_VOLUME , MERR_PATTERN }; #define PART_MAX 10 /* maximum count of programmed parts */ #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) \ || (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) #define MET_SYNC #endif #define METRONOME_QUIT PLA_EXIT #ifdef HAVE_SCROLLWHEEL #define METRONOME_VOL_UP PLA_SCROLL_FWD #define METRONOME_VOL_UP_REP PLA_SCROLL_FWD_REPEAT #define METRONOME_VOL_DOWN PLA_SCROLL_BACK #define METRONOME_VOL_DOWN_REP PLA_SCROLL_BACK_REPEAT #else #define METRONOME_VOL_UP PLA_UP #define METRONOME_VOL_DOWN PLA_DOWN #define METRONOME_VOL_UP_REP PLA_UP_REPEAT #define METRONOME_VOL_DOWN_REP PLA_DOWN_REPEAT #endif #define METRONOME_LEFT PLA_LEFT #define METRONOME_RIGHT PLA_RIGHT #define METRONOME_LEFT_REP PLA_LEFT_REPEAT #define METRONOME_RIGHT_REP PLA_RIGHT_REPEAT #define METRONOME_TAP PLA_SELECT_REL #define METRONOME_PAUSE PLA_CANCEL #define METRONOME_PLAY PLA_SELECT_REPEAT #define METRONOME_START PLA_SELECT #ifdef MET_SYNC enum{ METRONOME_SYNC = LAST_PLUGINLIB_ACTION+1 }; static const struct button_mapping iriver_syncaction[] = { { METRONOME_SYNC, BUTTON_REC, BUTTON_NONE }, LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_PLUGIN) }; #endif /* IRIVER_H100_PAD||IRIVER_H300_PAD */ const struct button_mapping *plugin_contexts[] = { pla_main_ctx, #if defined(MET_SYNC) iriver_syncaction, #endif }; #define PLA_ARRAY_COUNT sizeof(plugin_contexts)/sizeof(plugin_contexts[0]) /* raw PCM */ static signed short tick_sound[] = { 32767,32764,32767,32767,32763,32767,32762,32767,32765,32767,32767 ,32766,32767,32766,32767,32767,32765,32767,32764,32767,32764,32767 ,32763,-32764,-32768,-32766,-32768,-32768,-32767,-32767,-32767,-32765,-32768 ,-32764,-32768,-32768,-32766,-32768,-32764,-32768,-32766,-32767,-32768,-32767 ,-32766,32763,32767,32763,32767,32767,32766,32767,32766,32767,32765 ,32767,32763,32767,32766,32767,32766,32767,32763,32767,32765,32767 ,32767,-32768,-32765,-32768,-32767,-32765,-32767,-32765,-32768,-32764,-32768 ,-32766,-32768,-32768,-32766,-32767,-32768,-32764,-32768,-32764,-32768,-32768 ,-32766,32716,32668,32620,32564,32520,32467,32418,32370,32316,32272 ,32214,32176,32114,32074,32020,31972,31922,31873,31823,31775,31726 ,31676,-31627,-31579,-31530,-31479,-31433,-31383,-31333,-31287,-31236,-31188 ,-31141,-31090,-31042,-30998,-30943,-30899,-30849,-30800,-30757,-30702,-30659 ,-30609,30561,30515,30463,30422,30365,30326,30273,30229,30177,30135 ,30084,30035,29995,29936,29903,29844,29802,29755,29706,29661,29614 ,29565,-29519,-29472,-29426,-29381,-29331,-29288,-29239,-29191,-29149,-29099 ,-29055,-29007,-28962,-28914,-28871,-28821,-28779,-28730,-28685,-28638,-28596 ,-28544,28496,28463,28404,28371,28314,28278,28225,28185,28136,28093 ,28048,28001,27956,27912,27865,27824,27773,27736,27682,27646,27593 ,27555,-27509,-27462,-27418,-27375,-27328,-27286,-27239,-27200,-27145,-27116 ,-27055,-27026,-26972,-26930,-26891,-26838,-26805,-26750,-26716,-26663,-26630 ,-26575,26534,26495,26448,26408,26360,26324,26272,26235,26188,26149 ,26101,26061,26016,25976,25930,25888,25847,25800,25763,25714,25676 ,25632,-25589,-25547,-25505,-25461,-25419,-25376,-25337,-25291,-25251,-25209 ,-25162,-25129,-25078,-25043,-24995,-24960,-24910,-24876,-24830,-24787,-24751 ,-24703,24663,24622,24583,24539,24499,24456,24418,24374,24334,24292 ,24252,24209,24173,24124,24092,24042,24011,23960,23930,23879,23845 ,23803,-23762,-23722,-23680,-23644,-23597,-23562,-23518,-23482,-23437,-23402 ,-23357,-23320,-23281,-23236,-23203,-23158,-23119,-23082,-23040,-23000,-22962 ,-22922,22885,22837,22809,22759,22728,22685,22644,22608,22567,22528 ,22491,22449,22412,22372,22334,22295,22254,22221,22173,22146,22096 ,22066,-22026,-21984,-21947,-21911,-21867,-21836,-21790,-21757,-21719,-21677 ,-21644,-21601,-21567,-21526,-21489,-21454,-21411,-21378,-21337,-21301,-21263 ,-21226,21189,21151,21111,21077,21036,21002,20964,20926,20889,20852 ,20814,20779,20741,20703,20666,20632,20590,20562,20512,20490,20440 ,20416,-20380,-20331,-20303,-20261,-20230,-20188,-20158,-20114,-20085,-20045 ,-20009,-19975,-19935,-19904,-19864,-19829,-19797,-19753,-19726,-19685,-19650 ,-19616,19580,19544,19508,19471,19441,19397,19373,19325,19301,19256 ,19229,19189,19155,19122,19081,19055,19013,18980,18947,18908,18879 ,18840,-18807,-18771,-18739,-18701,-18669,-18634,-18600,-18564,-18531,-18497 ,-18461,-18430,-18392,-18360,-18326,-18291,-18258,-18223,-18191,-18154,-18123 ,-18088,18055,18019,17989,17953,17919,17887,17853,17817,17791,17746 ,17726,17680,17656,17619,17585,17555,17519,17488,17453,17423,17385 ,17359,17320,-17287,-17261,-17220,-17196,-17156,-17128,-17093,-17062,-17029 ,-16996,-16966,-16929,-16901,-16868,-16834,-16804,-16769,-16741,-16705,-16675 ,-16644,-16609,16579,16545,16519,16479,16455,16419,16388,16359,16321 ,16300,16256,16235,16198,16166,16141,16102,16076,16043,16011,15981 ,15950,15920,-15891,-15852,-15832,-15789,-15768,-15732,-15703,-15672,-15642 ,-15609,-15582,-15548,-15521,-15487,-15459,-15426,-15401,-15364,-15339,-15305 ,-15275,-15250,15219,15184,15159,15122,15101,15061,15041,15002,14981 ,14944,14919,14886,14858,14829,14797,14772,14736,14715,14675,14657 ,14617,14598,-14567,-14533,-14506,-14475,-14447,-14419,-14389,-14358,-14334 ,-14299,-14277,-14241,-14218,-14186,-14158,-14131,-14100,-14072,-14046,-14012 ,-13991,-13955,13927,13904,13873,13844,13819,13787,13761,13732,13706 ,13674,13651,13619,13590,13570,13530,13516,13475,13457,13423,13401 ,13368,13345,-13317,-13287,-13260,-13234,-13204,-13178,-13152,-13122,-13098 ,-13068,-13043,-13013,-12990,-12958,-12937,-12902,-12884,-12849,-12829,-12798 ,-12771,-12746,12718,12693,12663,12641,12611,12586,12559,12531,12510 ,12475,12459,12421,12408,12367,12357,12315,12301,12268,12244,12218 ,12194,12164,-12140,-12113,-12093,-12056,-12043,-12008,-11987,-11961,-11931 ,-11911,-11884,-11855,-11836,-11804,-11782,-11757,-11729,-11708,-11679,-11655 ,-11631,-11601,11574,11560,11525,11508,11479,11454,11431,11403,11382 ,11356,11329,11307,11279,11260,11229,11211,11179,11161,11133,11110 ,11085,11061,-11038,-11010,-10991,-10960,-10944,-10913,-10893,-10866,-10845 ,-10818,-10796,-10772,-10747,-10725,-10699,-10676,-10653,-10629,-10605,-10580 ,-10561,-10531,10507,10491,10461,10442,10416,10394,10369,10350,10319 ,10305,10276,10252,10236,10202,10190,10160,10138,10117,10093,10070 ,10050,10020,-9997,-9984,-9953,-9935,-9912,-9885,-9871,-9840,-9823 ,-9799,-9773,-9756,-9730,-9710,-9687,-9664,-9642,-9620,-9598,-9576 ,-9554,-9532,9510,9488,9466,9444,9419,9405,9374,9361,9331 ,9314,9293,9268,9250,9225,9206,9184,9160,9143,9118,9098 ,9077,9053,-9029,-9018,-8988,-8973,-8948,-8928,-8906,-8888,-8862 ,-8848,-8819,-8805,-8780,-8760,-8740,-8720,-8695,-8681,-8653,-8638 ,-8615,-8594,8573,8556,8531,8515,8492,8472,8451,8433,8409 ,8393,8368,8354,8326,8315,8284,8277,8243,8236,8206,8192 ,8170,8151,-8133,-8107,-8095,-8068,-8054,-8030,-8014,-7991,-7975 ,-7953,-7933,-7916,-7894,-7876,-7857,-7836,-7818,-7799,-7778,-7761 ,-7740,-7720,7700,7684,7665,7645,7626,7610,7582,7577,7545 ,7534,7513,7493,7477,7455,7438,7419,7402,7379,7368,7341 ,7328,7307,-7289,-7272,-7250,-7237,-7216,-7196,-7183,-7157,-7146 ,-7123,-7108,-7091,-7065,-7058,-7030,-7020,-6998,-6979,-6965,-6944 ,-6927,-6911,6895,6870,6859,6836,6824,6800,6790,6763,6755 ,6730,6717,6699,6679,6667,6642,6632,6610,6596,6574,6564 ,6539,6529,6507,-6492,-6474,-6457,-6442,-6422,-6406,-6392,-6371 ,-6358,-6338,-6322,-6306,-6291,-6269,-6259,-6237,-6223,-6206,-6190 ,-6172,-6157,-6139,6123,6108,6088,6077,6057,6043,6025,6010 ,5992,5978,5962,5944,5928,5914,5897,5879,5869,5844,5837 ,5816,5799,5789,-5773,-5750,-5742,-5720,-5710,-5687,-5680,-5656 ,-5648,-5627,-5613,-5600,-5581,-5568,-5552,-5534,-5525,-5501,-5496 ,-5470,-5464,-5443,5430,5413,5402,5383,5370,5353,5343,5320 ,5314,5292,5280,5267,5248,5237,5219,5208,5190,5176,5162 ,5148,5131,5121,-5107,-5086,-5077,-5058,-5047,-5030,-5017,-5002 ,-4990,-4971,-4963,-4941,-4935,-4915,-4902,-4892,-4869,-4867,-4841 ,-4836,-4816,-4806,4792,4774,4767,4744,4740,4716,4712,4692 ,4680,4668,4649,4642,4624,4612,4599,4584,4570,4560,4541 ,4535,4513,4508,-4496,-4472,-4467,-4450,-4437,-4427,-4407,-4401 ,-4384,-4372,-4358,-4346,-4331,-4322,-4305,-4294,-4281,-4266,-4257 ,-4240,-4231,-4216,4204,4190,4180,4162,4156,4137,4131,4111 ,4104,4091,4075,4068,4048,4043,4026,4016,4002,3990,3980 ,3962,3957,3938,-3926,-3919,-3904,-3892,-3882,-3866,-3858,-3843 ,-3833,-3820,-3810,-3792,-3789,-3769,-3762,-3751,-3732,-3730,-3710 ,-3704,-3689,-3678,3666,3656,3640,3637,3615,3613,3594,3586 ,3576,3560,3555,3537,3529,3518,3504,3497,3481,3473,3462 ,3447,3441,3425,-3414,-3406,-3394,-3383,-3372,-3359,-3353,-3336 ,-3330,-3316,-3306,-3295,-3287,-3270,-3266,-3251,-3241,-3233,-3218 ,-3210,-3197,-3192,3182,3160,3165,3139,3140,3121,3116,3104 ,3093,3083,3075,3057,3058,3038,3033,3021,3009,3003,2990 ,2981,2969,2960,-2947,-2943,-2928,-2921,-2910,-2898,-2891,-2881 ,-2868,-2863,-2846,-2846,-2826,-2824,-2810,-2800,-2795,-2779,-2774 ,-2763,-2751,-2746,2735,2724,2715,2705,2697,2682,2682,2662 ,2663,2645,2641,2629,2620,2612,2602,2592,2585,2572,2566 ,2557,2544,2540,-2530,-2520,-2508,-2503,-2492,-2482,-2477,-2463 ,-2457,-2447,-2439,-2430,-2419,-2416,-2398,-2399,-2382,-2380,-2365 ,-2364,-2346,-2345,2335,2324,2316,2308,2301,2290,2281,2275 ,2263,2262,2241,2250,2220,2232,2211,2208,2199,2189,2180 ,2177,2161,2163,-2154,-2137,-2138,-2119,-2122,-2102,-2107,-2087 ,-2088,-2073,-2073,-2055,-2057,-2040,-2040,-2027,-2022,-2013,-2005 ,-1997,-1991,-1981,1973,1967,1959,1953,1940,1941,1922,1928 ,1908,1911,1892,1896,1879,1882,1862,1866,1850,1847,1840 ,1829,1827,1815,-1809,-1802,-1797,-1785,-1784,-1770,-1768,-1757 ,-1755,-1742,-1740,-1729,-1724,-1716,-1711,-1701,-1697,-1688,-1682 ,-1676,-1665,-1663,1654,1649,1638,1637,1624,1622,1611,1611 ,1594,1599,1582,1582,1573,1566,1560,1554,1547,1538,1538 ,1523,1524,1512,1509,-1502,-1493,-1491,-1480,-1478,-1469,-1462 ,-1458,-1450,-1444,-1441,-1427,-1431,-1414,-1418,-1405,-1400,-1397 ,-1385,-1388,-1371,-1376,1370,1354,1355,1345,1341,1334,1329 ,1323,1316,1311,1305,1299,1294,1287,1282,1276,1270,1266 ,1255,1258,1244,1244,-1239,-1226,-1231,-1212,-1220,-1205,-1202 ,-1199,-1190,-1186,-1182,-1173,-1171,-1163,-1158,-1156,-1145,-1145 ,-1136,-1131,-1128,-1121,1116,1111,1106,1100,1094,1092,1082 ,1084,1068,1075,1061,1061,1053,1047,1047,1037,1036,1025 ,1027,1016,1017,1007,-1005,-996,-998,-986,-986,-980,-973 ,-973,-962,-962,-956,-949,-949,-939,-938,-931,-929,-920 ,-921,-911,-911,-903,899,896,891,885,880,881,869 ,873,858,863,853,851,847,840,840,829,833,819 ,826,811,815,804,-801,-800,-794,-788,-791,-778,-780 ,-774,-766,-771,-755,-764,-747,-754,-742,-743,-736,-734 ,-728,-727,-718,-720,715,708,708,699,703,687,697 ,681,687,675,679,665,675,657,665,653,654,648 ,646,642,637,634,-629,-629,-621,-623,-614,-615,-607 ,-607,-602,-599,-594,-594,-586,-588,-577,-583,-571,-574 ,-567,-564,-562,-559,557,548,552,541,546,532,542 ,527,531,524,522,521,515,513,509,507,504,500 ,497,495,490,489,-485,-482,-479,-476,-474,-468,-470 ,-462,-462,-458,-455,-454,-449,-447,-443,-442,-437,-437 ,-432,-429,-429,-422,420,419,417,412,411,409,404 ,403,400,397,394,393,388,388,382,384,375,381 ,371,372,369,364,-360,-365,-355,-360,-351,-354,-347 ,-347,-345,-340,-341,-336,-335,-331,-333,-323,-329,-322 ,-319,-321,-314,-316,314,308,308,303,304,300,298 ,297,292,294,288,288,285,281,285,275,279,276 ,270,272,269,264,-260,-267,-257,-261,-256,-254,-254 ,-249,-250,-247,-244,-245,-238,-242,-235,-237,-233,-232 ,-229,-229,-225,-225,222,222,218,218,214,215,211 ,212,206,210,201,206,202,199,199,197,192,197 ,191,188,192,183,-185,-179,-189,-174,-183,-177,-174 ,-178,-169,-174,-168,-169,-167,-165,-165,-161,-162,-158 ,-160,-155,-155,-155,154,149,151,148,147,146,143 ,145,138,144,136,139,136,134,136,129,135,125 ,134,123,130,120,-119,-126,-118,-123,-116,-122,-111 ,-120,-113,-111,-115,-108,-111,-109,-108,-104,-107,-103 ,-106,-99,-104,-94,93,100,95,98,93,97,88 ,96,85,96,84,91,85,84,89,81,84,82 ,79,84,75,82,75,-76,-75,-76,-73,-74,-71 ,-73,-70,-68,-72,-65,-70,-65,-65,-67,-61,-66 ,-62,-60,-62,-61,-57,54,64,52,61,52,57 ,54,54,53,53,50,53,48,53,45,53,43 ,51,45,45,47,42,-41,-45,-43,-40,-44,-39 ,-42,-40,-38,-38,-40,-36,-39,-34,-39,-32,-37 ,-33,-34,-34,-34,-29,28,35,28,32,29,30 ,27,31,27,28,27,26,27,24,30,20,28 ,21,27,20,27,18,-19,-23,-21,-22,-19,-23 ,-16,-24,-15,-23,-15,-21,-16,-17,-20,-14,-19 ,-14,-18,-13,-19,-11,11,18,10,19,8,17 ,13,10,18,5,18,7,16,8,12,11,10 ,10,12,6,14,5,-4,-14,-5,-10,-10,-5 ,-11,-6,-8,-8,-6,-9,-5,-7,-8,-2,-12 ,-1,-8,-6,-4,-7,6,5,4,7,2,6 ,4,3,8,1,4,4,4,3,5,1,5 ,3,1,5,2,3,-1,-5,-2,0,-5,1 ,-6,2,-6,3,-6,1,-5,2,-6,5,-8 ,4,-6,3,-5,3,-2,2,1,0,1,4 ,-5,6,-3,1,3,-2,3,-3,5,-5,5 ,-1,0,0,2,-3,4,-3,0,1,-1,-1 ,2,-2,1,-1,0,1,-1,0,0,0,1 ,-1,1,-2,2,-1,1,0,-3,5,-5,4 ,-1,-2,2,-1,1,0,-1,1,-1,2,-3 ,3,-3 }; static signed short tock_sound[] = { 32767,32761,32767,32762,32767,32763,32767,32765,32767,32767,32766 ,32767,32764,32767,32765,32767,32763,32767,32761,32767,32765,32767 ,32766,32767,32766,32767,32767,32764,32767,32763,32767,32767,32766 ,32767,32766,32767,32767,32765,32767,32763,32767,32761,32767,32764 ,32767,-32766,-32768,-32765,-32767,-32768,-32762,-32768,-32762,-32768,-32768 ,-32765,-32768,-32765,-32768,-32766,-32766,-32766,-32766,-32768,-32766,-32768 ,-32766,-32768,-32767,-32768,-32766,-32768,-32767,-32767,-32768,-32763,-32768 ,-32765,-32768,-32768,-32765,-32768,-32767,-32768,-32768,-32767,-32766,-32768 ,-32767,32720,32666,32619,32567,32516,32471,32414,32373,32314,32270 ,32220,32167,32123,32068,32023,31970,31924,31872,31824,31775,31725 ,31678,31625,31581,31527,31482,31431,31383,31334,31286,31238,31185 ,31144,31087,31046,30993,30947,30898,30848,30804,30750,30709,30653 ,30614,-30566,-30509,-30470,-30415,-30371,-30322,-30276,-30226,-30181,-30131 ,-30085,-30039,-29988,-29945,-29894,-29849,-29800,-29756,-29707,-29658,-29617 ,-29562,-29522,-29473,-29425,-29380,-29334,-29283,-29242,-29193,-29145,-29103 ,-29051,-29011,-28959,-28917,-28866,-28827,-28773,-28735,-28682,-28641,-28591 ,-28550,28503,28457,28407,28369,28316,28275,28229,28182,28137,28094 ,28044,28006,27952,27915,27864,27823,27775,27734,27682,27645,27597 ,27550,27513,27455,27426,27368,27333,27284,27240,27197,27152,27105 ,27069,27012,26982,26926,26891,26841,26799,26756,26712,26666,26628 ,26574,-26528,-26502,-26443,-26410,-26362,-26318,-26277,-26233,-26189,-26147 ,-26103,-26059,-26019,-25973,-25931,-25888,-25846,-25801,-25763,-25714,-25675 ,-25633,-25587,-25549,-25502,-25463,-25419,-25378,-25333,-25294,-25249,-25208 ,-25167,-25123,-25084,-25037,-25000,-24954,-24917,-24871,-24832,-24788,-24748 ,-24706,24665,24622,24582,24539,24501,24454,24420,24371,24336,24292 ,24251,24212,24167,24131,24084,24052,24001,23969,23921,23886,23842 ,23804,23760,23724,23678,23644,23598,23561,23521,23478,23440,23401 ,23356,23324,23275,23243,23197,23161,23118,23082,23039,23003,22959 ,22922,-22882,-22844,-22801,-22763,-22729,-22679,-22653,-22601,-22569,-22529 ,-22488,-22453,-22409,-22374,-22331,-22297,-22254,-22220,-22176,-22141,-22100 ,-22064,-22024,-21985,-21947,-21910,-21869,-21833,-21794,-21754,-21721,-21675 ,-21645,-21601,-21566,-21529,-21486,-21455,-21410,-21380,-21335,-21304,-21258 ,-21232,21195,21144,21118,21072,21038,21003,20960,20932,20882,20858 ,20810,20781,20740,20703,20668,20628,20595,20557,20518,20483,20447 ,20409,20374,20336,20299,20265,20225,20194,20150,20123,20079,20047 ,20008,19975,19937,19902,19866,19827,19797,19755,19725,19682,19654 ,19614,-19581,-19540,-19512,-19471,-19437,-19405,-19362,-19335,-19292,-19264 ,-19223,-19194,-19151,-19124,-19082,-19053,-19014,-18980,-18946,-18911,-18876 ,-18842,-18804,-18775,-18735,-18704,-18668,-18634,-18598,-18568,-18527,-18500 ,-18460,-18428,-18394,-18360,-18324,-18295,-18254,-18225,-18190,-18154,-18124 ,-18087,18054,18021,17987,17953,17921,17884,17855,17818,17786,17754 ,17718,17685,17654,17619,17586,17554,17519,17488,17454,17421,17387 ,17358,17319,17295,17251,17230,17186,17164,17123,17096,17061,17028 ,16996,16967,16929,16902,16865,16837,16801,16774,16736,16708,16675 ,16641,16612,-16578,-16549,-16513,-16486,-16449,-16423,-16385,-16361,-16321 ,-16297,-16260,-16233,-16198,-16169,-16137,-16102,-16080,-16038,-16017,-15976 ,-15954,-15914,-15892,-15855,-15826,-15796,-15762,-15735,-15702,-15673,-15638 ,-15617,-15572,-15556,-15515,-15489,-15461,-15424,-15400,-15365,-15338,-15304 ,-15281,-15241,15212,15189,15155,15125,15098,15064,15038,15005,14977 ,14947,14918,14886,14859,14827,14799,14771,14738,14711,14681,14651 ,14623,14592,14565,14532,14508,14474,14449,14416,14391,14357,14334 ,14301,14273,14246,14214,14188,14159,14128,14104,14069,14046,14016 ,13986,13958,-13928,-13905,-13869,-13849,-13816,-13789,-13758,-13736,-13702 ,-13678,-13649,-13616,-13598,-13561,-13539,-13508,-13480,-13455,-13424,-13399 ,-13371,-13341,-13318,-13284,-13263,-13232,-13205,-13179,-13150,-13124,-13096 ,-13069,-13041,-13017,-12984,-12965,-12930,-12908,-12881,-12849,-12831,-12793 ,-12779,-12739,12714,12694,12666,12636,12616,12583,12561,12531,12509 ,12476,12459,12421,12406,12373,12347,12325,12294,12271,12244,12218 ,12194,12164,12142,12112,12091,12062,12038,12009,11989,11956,11939 ,11903,11888,11855,11834,11806,11782,11755,11732,11705,11679,11658 ,11628,11605,-11579,-11557,-11527,-11505,-11480,-11455,-11429,-11406,-11380 ,-11355,-11331,-11305,-11283,-11256,-11231,-11210,-11178,-11166,-11126,-11117 ,-11080,-11063,-11037,-11010,-10992,-10961,-10940,-10916,-10890,-10871,-10838 ,-10825,-10791,-10774,-10747,-10724,-10699,-10679,-10648,-10634,-10600,-10586 ,-10554,-10537,10513,10485,10466,10438,10420,10391,10370,10349,10321 ,10305,10273,10257,10228,10211,10183,10164,10138,10115,10096,10066 ,10053,10019,10007,9975,9960,9930,9916,9883,9871,9839,9823 ,9801,9771,9759,9726,9714,9684,9666,9640,9623,9596,9577 ,9553,9532,-9510,-9487,-9467,-9443,-9422,-9401,-9377,-9358,-9334 ,-9313,-9292,-9270,-9248,-9227,-9205,-9182,-9165,-9138,-9121,-9098 ,-9075,-9057,-9032,-9015,-8989,-8973,-8947,-8929,-8907,-8885,-8867 ,-8842,-8824,-8802,-8780,-8763,-8737,-8720,-8699,-8676,-8657,-8637 ,-8614,-8597,8576,8554,8532,8513,8494,8470,8454,8429,8413 ,8390,8371,8351,8328,8314,8286,8274,8247,8233,8207,8192 ,8170,8149,8134,8108,8092,8070,8053,8031,8014,7991,7974 ,7953,7935,7912,7899,7872,7861,7832,7820,7798,7779,7761 ,7739,7724,-7706,-7679,-7669,-7641,-7628,-7607,-7588,-7570,-7551 ,-7530,-7515,-7491,-7478,-7456,-7438,-7419,-7401,-7379,-7369,-7338 ,-7335,-7300,-7295,-7267,-7255,-7233,-7218,-7196,-7181,-7159,-7145 ,-7124,-7107,-7090,-7068,-7055,-7033,-7018,-6999,-6979,-6966,-6942 ,-6929,-6909,6891,6875,6855,6840,6820,6803,6787,6768,6750 ,6733,6717,6695,6687,6657,6650,6629,6608,6599,6573,6562 ,6543,6525,6508,6494,6470,6462,6437,6426,6405,6391,6371 ,6358,6338,6323,6305,6289,6273,6254,6241,6221,6206,6191 ,6170,6160,6136,-6121,-6108,-6090,-6075,-6057,-6044,-6023,-6013 ,-5988,-5983,-5955,-5950,-5926,-5914,-5897,-5879,-5867,-5846,-5837 ,-5813,-5806,-5780,-5774,-5751,-5741,-5720,-5710,-5687,-5680,-5656 ,-5648,-5626,-5616,-5596,-5584,-5566,-5552,-5538,-5519,-5507,-5490 ,-5475,-5463,-5440,5425,5419,5396,5385,5373,5350,5342,5324 ,5308,5297,5278,5266,5250,5236,5218,5209,5190,5176,5162 ,5148,5131,5120,5103,5088,5075,5061,5043,5035,5013,5005 ,4988,4973,4960,4946,4931,4916,4905,4885,4879,4856,4850 ,4829,4823,4799,-4785,-4783,-4758,-4749,-4738,-4718,-4710,-4693 ,-4679,-4669,-4649,-4643,-4621,-4616,-4596,-4585,-4572,-4555,-4548 ,-4527,-4521,-4501,-4492,-4477,-4464,-4451,-4437,-4425,-4410,-4399 ,-4384,-4372,-4359,-4345,-4332,-4320,-4307,-4292,-4283,-4265,-4256 ,-4243,-4227,-4217,4201,4196,4171,4173,4145,4147,4123,4117 ,4103,4087,4079,4065,4051,4042,4026,4014,4005,3988,3981 ,3962,3956,3939,3931,3917,3903,3892,3882,3866,3860,3841 ,3831,3824,3804,3800,3782,3772,3761,3749,3737,3726,3712 ,3702,3690,3679,-3667,-3656,-3640,-3637,-3614,-3614,-3594,-3587 ,-3573,-3564,-3549,-3542,-3528,-3517,-3506,-3494,-3482,-3475,-3458 ,-3452,-3437,-3427,-3417,-3406,-3392,-3384,-3372,-3359,-3354,-3335 ,-3330,-3316,-3306,-3297,-3283,-3276,-3259,-3256,-3239,-3232,-3220 ,-3210,-3196,-3192,3182,3161,3161,3143,3137,3124,3114,3103 ,3096,3080,3075,3060,3054,3040,3034,3018,3013,2999,2992 ,2980,2971,2958,2953,2937,2933,2918,2910,2901,2889,2881 ,2869,2862,2849,2842,2828,2824,2810,2801,2793,2780,2774 ,2762,2755,2740,-2730,-2729,-2711,-2706,-2697,-2683,-2681,-2665 ,-2658,-2650,-2636,-2633,-2618,-2614,-2599,-2593,-2585,-2571,-2568 ,-2556,-2542,-2544,-2521,-2526,-2507,-2502,-2492,-2483,-2474,-2467 ,-2455,-2447,-2440,-2428,-2422,-2412,-2402,-2396,-2385,-2376,-2369 ,-2359,-2351,-2344,2336,2323,2319,2303,2306,2282,2290,2269 ,2268,2254,2251,2238,2234,2221,2217,2203,2203,2187,2184 ,2171,2168,2155,2150,2141,2132,2125,2116,2109,2099,2094 ,2083,2078,2066,2062,2052,2045,2037,2027,2023,2011,2009 ,1994,1992,1980,-1973,-1967,-1959,-1950,-1945,-1937,-1926,-1923 ,-1911,-1907,-1899,-1889,-1885,-1873,-1871,-1860,-1853,-1847,-1838 ,-1832,-1824,-1816,-1811,-1801,-1795,-1789,-1778,-1776,-1765,-1759 ,-1753,-1742,-1742,-1726,-1728,-1714,-1710,-1703,-1696,-1688,-1682 ,-1676,-1664,-1667,1661,1641,1645,1632,1625,1625,1607,1612 ,1596,1596,1585,1581,1570,1571,1556,1556,1546,1539,1536 ,1525,1523,1512,1511,1497,1499,1487,1481,1480,1465,1466 ,1455,1450,1447,1436,1434,1423,1420,1414,1407,1401,1395 ,1388,1382,1379,1369,-1364,-1359,-1352,-1348,-1338,-1336,-1328 ,-1322,-1318,-1310,-1305,-1300,-1291,-1290,-1280,-1277,-1269,-1267 ,-1256,-1255,-1246,-1242,-1238,-1228,-1225,-1221,-1212,-1209,-1203 ,-1195,-1193,-1186,-1180,-1175,-1170,-1163,-1161,-1150,-1150,-1142 ,-1137,-1133,-1126,-1119,1113,1112,1105,1100,1096,1089,1084 ,1080,1075,1068,1067,1054,1059,1045,1045,1041,1031,1031 ,1022,1018,1016,1007,1006,997,996,987,986,979,975 ,970,966,959,957,949,948,940,939,928,932,920 ,918,915,907,906,-900,-896,-890,-885,-883,-877,-871 ,-870,-862,-860,-856,-848,-848,-841,-837,-834,-827,-827 ,-817,-817,-811,-808,-803,-798,-794,-791,-786,-783,-777 ,-774,-769,-765,-763,-756,-754,-748,-746,-741,-737,-732 ,-731,-722,-727,-710,707,714,704,700,702,690,693 ,684,685,676,677,671,665,668,656,657,653,649 ,644,645,632,640,626,631,620,623,614,615,607 ,608,601,598,598,588,592,582,584,576,577,568 ,571,564,561,558,-554,-553,-546,-546,-541,-540,-532 ,-537,-522,-531,-519,-521,-515,-513,-510,-505,-507,-495 ,-503,-489,-495,-486,-486,-481,-480,-476,-472,-472,-465 ,-467,-458,-461,-453,-455,-450,-444,-446,-439,-441,-433 ,-435,-428,-428,-425,424,416,417,413,411,407,407 ,401,400,397,396,389,394,381,388,379,381,375 ,376,368,371,365,365,360,360,356,353,353,347 ,347,346,340,339,339,331,337,326,330,323,325 ,319,321,312,318,-316,-305,-310,-303,-303,-302,-296 ,-298,-292,-293,-289,-288,-285,-283,-281,-279,-278,-274 ,-273,-269,-271,-265,-265,-264,-257,-262,-255,-254,-255 ,-248,-250,-247,-243,-247,-236,-244,-232,-240,-231,-232 ,-232,-223,-232,-220,219,224,217,218,216,212,212 ,212,207,208,204,202,204,200,197,197,195,193 ,194,187,191,186,184,187,177,186,175,180,175 ,173,175,169,172,168,165,167,162,166,157,162 ,156,158,156,152,-152,-151,-149,-149,-146,-147,-142 ,-145,-140,-141,-138,-137,-139,-131,-138,-128,-135,-126 ,-132,-124,-129,-123,-125,-121,-123,-116,-123,-116,-117 ,-115,-113,-114,-112,-112,-107,-110,-108,-104,-109,-100 ,-105,-103,-99,-101,99,99,94,98,93,96,89 ,96,87,91,88,89,86,88,81,86,83,82 ,82,78,83,73,83,73,77,76,72,74,73 ,69,73,70,67,71,63,71,62,69,59,68 ,58,66,58,63,57,-58,-58,-57,-56,-56,-55 ,-56,-51,-57,-47,-56,-48,-53,-49,-48,-50,-45 ,-50,-45,-46,-46,-43,-45,-43,-43,-41,-43,-39 ,-43,-37,-42,-35,-42,-34,-39,-36,-36,-35,-35 ,-34,-34,-34,-31,-35,35,28,34,27,35,23 ,35,23,32,26,27,28,24,28,23,27,24 ,24,25,21,25,22,22,23,19,23,20,20 ,22,16,23,15,23,13,23,12,23,13,18 ,16,15,16,16,14,-14,-14,-16,-11,-18,-9 ,-17,-8,-17,-10,-14,-10,-11,-13,-10,-12,-9 ,-10,-11,-9,-11,-8,-9,-10,-6,-13,-4,-12 ,-4,-12,-2,-14,-1,-12,-3,-8,-6,-7,-6 ,-6,-5,-6,-5,-6,6,3,8,2,7,2 ,7,2,6,1,6,4,1,9,-5,12,-5 ,10,-1,5,0,5,1,5,0,3,3,1 ,3,2,1,3,0,5,-2,4,0,2,3 ,-1,4,-3,6,-3,2,-2,-2,0,-1,-2 ,1,-1,-2,1,-2,0,0,-2,2,-3,2 ,-4,4,-5,5,-5,2,0,-1,0,1,-4 ,5,-5,4,-3,2,-1,-1,1,-2,2,-2 ,2,-2,2,-1,0,1,-1,0,1,-2,3 ,-3,2,-1,0,1,-1,0,0,1,-1,1 ,-2,3 }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Utilities from pdbox plugin (Copyright (C) 2009 Wincent Balin) --- am I supposed to supply these functions with the plugin? Should I use a library? * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Implementation of strtod() and atof(), taken from SanOS (http://www.jbox.dk/sanos/). */ static int rb_errno = 0; static double rb_strtod(const char *str, char **endptr) { double number; int exponent; int negative; char *p = (char *) str; double p10; int n; int num_digits; int num_decimals; /* Reset Rockbox errno -- W.B. */ #ifdef ROCKBOX rb_errno = 0; #endif // Skip leading whitespace while (isspace(*p)) p++; // Handle optional sign negative = 0; switch (*p) { case '-': negative = 1; // Fall through to increment position case '+': p++; } number = 0.; exponent = 0; num_digits = 0; num_decimals = 0; // Process string of digits while (isdigit(*p)) { number = number * 10. + (*p - '0'); p++; num_digits++; } // Process decimal part if (*p == '.') { p++; while (isdigit(*p)) { number = number * 10. + (*p - '0'); p++; num_digits++; num_decimals++; } exponent -= num_decimals; } if (num_digits == 0) { #ifdef ROCKBOX rb_errno = 1; #else errno = ERANGE; #endif return 0.0; } // Correct for sign if (negative) number = -number; // Process an exponent string if (*p == 'e' || *p == 'E') { // Handle optional sign negative = 0; switch(*++p) { case '-': negative = 1; // Fall through to increment pos case '+': p++; } // Process string of digits n = 0; while (isdigit(*p)) { n = n * 10 + (*p - '0'); p++; } if (negative) exponent -= n; else exponent += n; } #ifndef ROCKBOX if (exponent < DBL_MIN_EXP || exponent > DBL_MAX_EXP) { errno = ERANGE; return HUGE_VAL; } #endif // Scale the result p10 = 10.; n = exponent; if (n < 0) n = -n; while (n) { if (n & 1) { if (exponent < 0) number /= p10; else number *= p10; } n >>= 1; p10 *= p10; } #ifndef ROCKBOX if (number == HUGE_VAL) errno = ERANGE; #endif if (endptr) *endptr = p; return number; } static double rb_atof(const char *str) { return rb_strtod(str, NULL); } /* * * * * * * * * * * * * * * * * * * * * * * Actual metronome stuff * * * * * * * * * * * * * * * * * * * * * * */ static int fd = -1; /* file descriptor, global for cleanup(). */ /* Round fixed-point number to integer. */ static int fp_rint(long fp_num) { fp_num += fp_num > 0 ? +((long)1<<15) : -((long)1<<15); return (int)(fp_num / ((long)1<<16)); } /* float to fixed-point */ static long fp_frac(float fl_num) { return (long)(fl_num*((long)1<<16)); } /* simple dynamic memory management - only allocate blocks serially - deallocation of most recent blocks by resetting the free region pointer - everything aligned to 4 bytes (wasting some bytes, but playing safe) */ static void *mem_begin = NULL; /* beginning of managed region. */ static void *mem_end = NULL; /* just after end of managed region */ static void *mem_free_region = NULL; /* pointer to unused free space */ static void *mem_checkpointer = NULL; /* position to reset to */ /* Initialize memory management. */ static void mem_init(void) { size_t bufsize; /* Can I trust that pointer to be aligned? Better be safe. */ mem_begin = ALIGN_UP(rb->plugin_get_buffer(&bufsize), 4); mem_end = mem_begin + bufsize - 3; mem_free_region = mem_begin; mem_checkpointer = mem_begin; } /* Remember and reset free region, for temporary mem usage. */ static void mem_checkpoint(void){ mem_checkpointer = mem_free_region; } static void mem_reset (void){ mem_free_region = mem_checkpointer; } static void *mem_allocate(size_t bytes) { void *handout = mem_free_region; /* Always handing out multiples of alignment size. */ if(bytes % 4) bytes += 4 - bytes % 4; if(mem_free_region + bytes >= mem_end) { rb->splash(2*HZ, "Out Of Memory"); return NULL; } mem_free_region += bytes; return handout; } struct part; struct part /* One part of a track, with one tempo (range), meter, etc. */ { struct part *prev, *next; /* linked list links*/ unsigned int id; /* index (in order, please) */ char *label; unsigned int bars; /* Duration of part in bars. */ unsigned int beats_per_bar; /* 3 in 3/4 */ unsigned int base_beat; /* 4 in 3/4 to adjust bpm value */ unsigned int bpm; /* base tempo (1/4 notes per minute) */ unsigned int bpm2; /* end tempo */ unsigned int *beat_bpm; /* either NULL or (bars*beats_per_bar) values */ long accel; /* fixed-point acceleration in 1/min (really) */ int volume; /* volume offset in integer dB */ /* Store pattern characters verbatim for max. 64 beats (no string termination). One could save storage here by encoding things in bits, or by allocating dynamically to begin with. */ char *pattern; }; static struct part *part_list = NULL; /* linked list of parts */ static struct part *part = NULL; /* current part */ static unsigned int parts = 0; /* total number of parts */ static unsigned int bad_parts = 0; /* Count parts with parsing errors. */ /* Initialize a part that is not yet placed into the list. */ static void part_init(struct part *ps) { ps->prev = NULL; ps->next = NULL; ps->id = 0; ps->label = NULL; ps->bars = 0; ps->beats_per_bar = 4; ps->base_beat = 4; ps->bpm = 120; ps->bpm2 = 120; ps->beat_bpm = NULL; ps->accel = 0; ps->volume = 0; ps->pattern = NULL; } /* Add to the list. */ static void part_add(struct part *ps) { if(part) { part->next = ps; ps->prev = part; part = ps; } else part = part_list = ps; ps->id = parts++; } /* Stay away from zero. */ static unsigned int positive(long long value) { return value > 0 ? value : 1; } /* Yay! Global state variables! */ static bool track_mode = false; /* switch for programmed tracks metronome */ static int loop = 0; /* Needed? */ static unsigned int beat = 0; static unsigned int bar = 0; /* How big shall this become? */ /* The currently (approximate) active bpm value, set from calc_period(). */ static unsigned int bpm = 1; /* Should be unsigned? */ static unsigned int period = 0; /* beat interval in timer ticks */ static long period_diff = 0; /* fixed-point error of last period computation */ static unsigned int minitick = 0; /* elapsed ticks */ static bool beating = false; /* A beat is/was playing and count needs to increase. */ static int display_state = 0; /* Current display state code. */ static bool display_trigger = false; /* Draw display on next occasion */ static bool sound_active = false; static bool sound_paused = true; /* global static buffer for messages in any situation */ static char buffer[64]; /* For line parsing, more is needed, allocated on demand. As my memory management doesn't allow to free it, keeping it local ist not smart. */ static char* linebuf = NULL; size_t linebuf_size = 0; /* global state for tempo tapping */ static bool reset_tap = false; static int tap_count = 0; static int tap_time = 0; static int tap_timeout = 0; static int bpm_step_counter = 0; static bool sound_trigger = false; #define MET_IS_PLAYING rb->pcm_is_playing() #define MET_PLAY_STOP rb->audio_stop() /* Really necessary? Cannot just play mono? Also: This is wasted memory! */ static short tick_buf[sizeof(tick_sound)*2]; static short tock_buf[sizeof(tock_sound)*2]; /* Convert the mono samples to interleaved stereo */ static void prepare_buffers(void) { size_t i; for(i = 0;i < sizeof(tick_sound)/sizeof(short);i++) tick_buf[i*2] = tick_buf[i*2+1] = tick_sound[i]; for(i = 0;i < sizeof(tock_sound)/sizeof(short);i++) tock_buf[i*2] = tock_buf[i*2+1] = tock_sound[i]; } static void play_tick(void) { rb->pcm_play_data(NULL, NULL, tick_buf, sizeof(tick_buf)); } static void play_tock(void) { rb->pcm_play_data(NULL, NULL, tock_buf, sizeof(tock_buf)); } /* State: 0: blank/title, 1: tick, 2: tock 3: silent klick */ /* TODO: Could use more smart placement, using lcd_getstringsize() and such. */ static void metronome_draw(struct screen* display, int state) { struct part *ps; int textlen = display->lcdwidth / display->getcharwidth(); ps = part; display->clear_display(); display->setfont(FONT_SYSFIXED); switch(state) { case 0: if(sound_paused) { if(track_mode) display->puts(0, 0, "Metronome Track"); else display->puts(0, 0, "Metronome"); display->hline(0, display->lcdwidth, 12); } break; /* Draw odd/even ticks/tocks differently to be able to go without display clearing in between for fast beats. */ case 1: if((beat+1) % 2 == 0) display->fillrect( display->lcdwidth/2, 0 , display->lcdwidth, 12 ); else display->fillrect( 0, 0 , display->lcdwidth/2-1, 12 ); break; case 2: if((beat+1) % 2 == 0) display->fillrect( display->lcdwidth/2, display->lcdheight-13 , display->lcdwidth, 12 ); else display->fillrect( 0, display->lcdheight-13 , display->lcdwidth/2-1, 12 ); break; case 3: display->puts((textlen-3)/2,0, "o.O"); break; } if(track_mode) { /* One line in several. */ rb->snprintf( buffer, sizeof(buffer), "%u/%u@%u V%d" , ps->beats_per_bar, ps->base_beat , bpm, rb->global_settings->volume ); display->puts(0,4, buffer); /* Would it hurt to draw a 3rd line to 2-line display? I guess there are 3-line displays out there. */ if(ps->label && rb->strlen(ps->label)) { rb->snprintf(buffer, sizeof(buffer), "\"%s\"", ps->label); display->puts((textlen-rb->strlen(buffer))/2, 2, buffer); } /* Wildly guessing here with puts(). */ if(ps->bars) rb->snprintf( buffer, sizeof(buffer), "P%u/%u: B%u/%u+%u" , part->id+1, parts, bar+1, ps->bars, beat+1 ); else rb->snprintf( buffer, sizeof(buffer), "P%u/%u: B%u/_+%u" , part->id+1, parts, bar+1, beat+1 ); display->puts(0, 5, buffer); } else /* track mode */ { if(display->screen_type==SCREEN_MAIN) { #ifdef MET_SYNC display->puts(0, 5, "Select=TAP Rec=SYNC"); #else display->puts(0, 5, "Select=TAP"); #endif } #ifdef HAVE_REMOTE_LCD else { #ifdef MET_SYNC display->puts(0, 5, "Rec=TAP Mode=SYNC"); #else display->puts(0, 5, "Rec=TAP"); #endif } #endif rb->snprintf( buffer, sizeof(buffer), "BPM: %d Vol: %d" , bpm, rb->global_settings->volume ); display->puts(0,3, buffer); display->hline(0, 111, 12); if(sound_paused) display->puts(0,2,"start: hold select"); else display->puts(0,2,"stop : cancel"); } /* !track_mode */ display->setfont(FONT_UI); display->update(); } /* Trigger drawing of display at the next occasion using given state. */ static void trigger_display(int state) { display_state = state; display_trigger = true; } /* Actually draw display. */ static void draw_display(void) { FOR_NB_SCREENS(i) metronome_draw(rb->screens[i], display_state); } /* Modify actual volume by given offset without changing the configured one. This is for parts with associated volume. */ static void tweak_volume(int offset) { int vol = rb->global_settings->volume + offset; int minvol = rb->sound_min(SOUND_VOLUME); int maxvol = rb->sound_max(SOUND_VOLUME); if (vol > maxvol) vol = maxvol; else if(vol < minvol) vol = minvol; rb->sound_set(SOUND_VOLUME, vol); } /* tempo at a certain point in beat space in an accelerated part */ static long accel_tempo(struct part *ps, long offset) { long fp_bpm = (long)ps->bpm<<16; long fp_bpm2 = (long)ps->bpm2<<16; long v = fp_bpm + fp_mul(ps->accel, offset, 16); /* Offset could be negative, actually, so ensure tempo stays within both bounds */ if(ps->accel > 0) { if(v < fp_bpm) v = fp_bpm; if(v > fp_bpm2) v = fp_bpm2; } else /* deceleration */ { if(v > fp_bpm) v = fp_bpm; if(v < fp_bpm2) v = fp_bpm2; } return v; } /* Calculate number of ticks to wait till next beat. */ static void calc_period(void) { struct part *ps = part; long deltat; long beatlen; /* in quarter notes */ long period_fp; beatlen = fp_div(4<<16, ps->base_beat<<16, 16); /* Hack: Put the factor 60 in before computing deltat, to preserve some accuracty. */ if(ps->beat_bpm) { bpm = ps->beat_bpm[bar*ps->beats_per_bar+beat]; deltat = fp_div(fp_mul(60<<16,beatlen,16), bpm<<16, 16); } else if(ps->accel == 0.f) { /* Fixed tempo. */ bpm = ps->bpm; /* Minutes per base beat, from quarters per minute. */ deltat = fp_div(fp_mul(60<<16,beatlen,16), bpm<<16, 16); } else { /* Acceleration, varying period with each beat. */ long v0, v1; long offset = (bar*ps->beats_per_bar + beat) << 16; /* Always computed from start of part for seeking and accuracy. */ v0 = accel_tempo(ps, fp_mul(beatlen, offset, 16)); offset += 1<<16; v1 = accel_tempo(ps, fp_mul(beatlen, offset, 16)); /* Playing safe with too small tempo changes, avoiding the acceleration math that might divide by very small deltat. */ if(labs(v1-v0) > 1<<8) { /* deltat = 1.f / ps->accel * rb_log(v1/v0) */ deltat = fp_mul( fp_div(60<<16, ps->accel, 16) , fp16_log(fp_div(v1, v0, 16)) , 16 ); bpm = fp_rint(fp_div(fp_mul(60<<16, beatlen, 16), deltat, 16)); } else { /* Arbitrarily choosing v1. */ bpm = fp_rint(v1); deltat = fp_div(fp_mul(60<<16,beatlen,16), v1, 16); } } /* The treatment of the rounding error when converting to integer period using period_diff helps a lot to keep track lengths close to "correct" even with timerfreq_div as low as 77. Actually, I have _less_ drift than with timerfreq_div of 1000! */ period_fp = fp_mul(timerfreq_div<<16, deltat, 16) + period_diff; period = positive(fp_rint( period_fp )); period_diff = period_fp - (long)(period<<16); } /* Last beat finished, to prepare for the next one. */ static void advance_beat(void) { if(++beat == part->beats_per_bar) { beat = 0; /* Bar counter always incremented for acceleration, but only checked against a limit if there is one. */ ++bar; if(part->bars && bar == part->bars) { bar = 0; if(part->next) part = part->next; else { part = part_list; if(!loop) sound_paused = true; } tweak_volume(part->volume); } } /* Always recompute period, as acceleration changes it for each beat. */ calc_period(); } /* Decide what to play, update display, play it. Beat counting happens here, too. */ static void play_ticktock(void) { if(beating) advance_beat(); /* Hack: Clear trigger to avoid race condition. */ display_trigger = 0; if(sound_paused) { beating = false; display_state = 0; draw_display(); } else { char pat = 'x'; if(part->pattern) pat = part->pattern[beat]; beating = true; /* Blinking and specific sound for tick, tock and silent beat. Drawing display first for slow machines (YH820), to avoid interrupting audio for regular playback. */ switch(pat) { case 'X': display_state = 1; draw_display(); play_tick(); break; case 'x': display_state = 2; draw_display(); play_tock(); break; default: display_state = 3; draw_display(); } } } /* helper function to change the volume by a certain amount, +/- ripped from video.c */ static void change_volume(int delta) { int minvol = rb->sound_min(SOUND_VOLUME); int maxvol = rb->sound_max(SOUND_VOLUME); int vol = rb->global_settings->volume + delta; if (vol > maxvol) vol = maxvol; else if(vol < minvol) vol = minvol; if(vol != rb->global_settings->volume) { rb->global_settings->volume = vol; tweak_volume(part->volume); trigger_display(display_state); } } /*function to accelerate bpm change*/ static void change_bpm(int direction) { if( (bpm_step_counter < 20) || (bpm > 389) || (bpm < 10) ) bpm = bpm + direction; else if(bpm_step_counter < 60) bpm = bpm + direction * 2; else bpm = bpm + direction * 9; if(bpm > 400) bpm = 400; if(bpm < 1) bpm = 1; part->bpm = bpm; calc_period(); trigger_display(display_state); bpm_step_counter++; } /* I presume the timer ensures that not more than one instance of the callback is running at a given time. */ static void timer_callback(void) { ++minitick; /* Clear blinker if tempo is slow enough. */ if( (bpm*part->base_beat)/4 <= blinklimit && !sound_paused && minitick == period/2 ) trigger_display(0); if(minitick >= period) { minitick = 0; if(!sound_active && !sound_paused && !tap_count) { sound_trigger = true; rb->reset_poweroff_timer(); } } if(tap_count) { tap_time++; if(tap_count > 1 && tap_time > tap_timeout) tap_count = 0; } } /* Stopping playback means incrementing the beat. Normally, it would be incremented after the passing of the current note duration, naturally while starting the next one. */ static void metronome_pause(void) { if(beating) { /* Finish the current beat. */ advance_beat(); beating = false; } sound_paused = true; trigger_display(0); rb->timer_unregister(); } static void metronome_unpause(void) { sound_paused = false; minitick = period; /* Start playing immediately (or after a millisecond). */ /* Conserve power: Only start timer when actually playing. */ rb->timer_register( 1, NULL, TIMER_FREQ/timerfreq_div , timer_callback IF_COP(, CPU) ); } static void cleanup(void) { if(fd >= 0) rb->close(fd); metronome_pause(); MET_PLAY_STOP; /* stop audio ISR */ tweak_volume(0); rb->led(0); rb->pcm_set_frequency(HW_SAMPR_DEFAULT); } /* Parse part definitions from tempomap file (see header for format). Not bothering with encoding issues here. */ /* parse meter spec into part structure if given token matches */ static bool parse_meter(char *token, struct part *ps) { char *toktok; /* Careful not to misinterpret accelerated tempo specification: 120-150/4 -> tempo 3/4 -> meter */ if( !rb->strchr(token, '-') && (toktok = rb->strchr(token, '/')) ) { /* Number before and after the '/'. */ int num[2]; num[0] = rb->atoi(token); num[1] = rb->atoi(++toktok); /* Only accept positive numbers. */ if(num[0] > 0 && num[1] > 0) { ps->beats_per_bar = (unsigned int) num[0]; ps->base_beat = (unsigned int) num[1]; return true; } } return false; } /* Parse tempo, successful when getting a positive integer out of the token. */ static bool parse_tempo(char *token, struct part *ps) { char *toktok; /* tempo[-tempo2/accel] ... first number always main tempo */ int num = rb->atoi(token); /* Only positive numbers. This avoids the pattern string and general strangeness, unless -150 should mean "from previous tempo to 150". */ if(num < 1) return false; ps->bpm = (unsigned int) num; ps->bpm2 = ps->bpm; ps->accel = 0; /* This parser is not fool-proof. It parses valid data, but could do funny things if you provide tempo/tempo2-accel, for example. My credo is that the application doesn't crash, but if you give rubbish, you'll get rubbish. */ if( (toktok = rb->strchr(token, '-')) ) { char *subtok = toktok+1; float faccel = 0.; ps->bpm2 = positive(rb->atoi(subtok)); /* Parse or compute accel in bpm/bar. */ if( (toktok = rb->strchr(subtok, '/')) ) { /* bars/bpm */ float c = rb_atof(++toktok); if( (c > 0.f ? c : -c) > 0.0001f) faccel = 1./c; } else if( (toktok = rb->strchr(subtok, '*')) ) { /* bpm/bar */ faccel = rb_atof(++toktok); } else if(ps->bars > 0) { /* Compute from tempo difference and bar count. */ faccel = ((float)ps->bpm2 - (float)ps->bpm)/ps->bars; } /* Correct sign for all cases, starting with positive value. */ if(faccel < 0) faccel = -faccel; /* Negative only when end tempo is smaller. */ if(ps->bpm2 < ps->bpm) faccel = -faccel; /* Convert (quarterbeats-per-minute per bar) -> 1/min, which could be seen as beats-per-minute/beat */ faccel *= 1.f / (4.f/ps->base_beat * ps->beats_per_bar); /* 1/min */ ps->accel = fp_frac(faccel); } else /* The other fancy variant: One tempo per beat. */ if( (toktok = rb->strchr(token, ',')) ) { size_t i; char *subtok = token; /* It is a bug when the parser called this before. Alloc once. */ if( ps->beat_bpm || !(ps->beat_bpm = mem_allocate(sizeof(unsigned int)*ps->beats_per_bar*ps->bars)) ) return false; for(i=0; ibeats_per_bar*ps->bars; ++i) { int num; if(!subtok) return false; if(subtok != token) ++subtok; num = rb->atoi(subtok); if(num < 1) return false; ps->beat_bpm[i] = (unsigned int) num; subtok = rb->strchr(subtok, ','); } } return true; } /* The metronome pattern. Ensure that the correct meter is present before calling this! */ static bool parse_pattern(char *token, struct part *ps) { size_t pi; size_t pats = rb->strlen(token); /* First check if the pattern is valid, error out if not. */ if(pats != ps->beats_per_bar) return false; for(pi=0; pipattern || (ps->pattern = mem_allocate(pats)))) return false; /* Now store it. */ memcpy(ps->pattern, token, pats); return true; } static bool parse_volume(char *token, struct part *ps) { float factor = rb_atof(token); ps->volume = fp_rint(fp_decibels(fp_frac(factor > 0.f ? factor : 0.f), 16)); return true; } /* Check condition, set error code and bail out if violated. */ #define CHECK(a, c) if(!(a)){ errcode = c; goto parse_part_revert; } static void parse_part(char *line, unsigned int num) { char *saveptr; char *toktok; char *token[5]; struct part *ps; size_t tokens = 0; unsigned int errcode = MERR_NOTHING; while (isspace(*line)) line++; /* Skip comments and empty lines quickly. */ if(line[0] == '#' || line[0] == 0) return; mem_checkpoint(); CHECK(ps = mem_allocate(sizeof(struct part)), MERR_OOM); part_init(ps); /* Check for and store label. */ if( (toktok = rb->strchr(line, ':')) ) { size_t len = toktok-line; CHECK(ps->label = mem_allocate(len+1), MERR_OOM); rb->memcpy(ps->label, line, len); ps->label[len] = 0; line = toktok+1; } CHECK(token[0] = rb->strtok_r(line, " \t", &saveptr), MERR_MISSING); tokens = 1; /* After the optional label, there can be up to 5 tokens of interest. Collect them in advance to make the parser code more sane. */ while( tokens < 5 && (token[tokens] = rb->strtok_r(NULL, " \t", &saveptr)) ) { if(token[tokens][0] == '#') break; ++tokens; } CHECK(tokens >= 2, MERR_MISSING); /* Now try to be smart about guessing which token can be what value. Remember: Always parse meter before pattern or tempo! */ ps->bars = (unsigned int) rb->atoi(token[0]); if(tokens == 2) /* */ { CHECK(parse_tempo(token[1], ps), MERR_TEMPO); } else if(tokens == 3) { /* */ if(parse_meter(token[1], ps)) { CHECK(parse_tempo(token[2], ps), MERR_TEMPO); } else /* */ if(parse_pattern(token[2], ps)) { CHECK(parse_tempo(token[1], ps), MERR_TEMPO); } else /* */ { CHECK(parse_tempo(token[1], ps), MERR_TEMPO); CHECK(parse_volume(token[2], ps), MERR_VOLUME); } } else if(tokens == 4) { /* */ if(parse_meter(token[1], ps) && parse_pattern(token[3], ps)) { CHECK(parse_tempo(token[2], ps), MERR_TEMPO); } else /* */ if(parse_pattern(token[2], ps)) { CHECK(parse_tempo(token[1], ps), MERR_TEMPO); CHECK(parse_volume(token[3], ps), MERR_VOLUME); } else /* */ { CHECK(parse_meter(token[1], ps), MERR_METER); CHECK(parse_tempo(token[2], ps), MERR_TEMPO); CHECK(parse_volume(token[3], ps), MERR_VOLUME); } } else if(tokens == 5) /* the complete set */ { /* */ CHECK(parse_meter(token[1], ps), MERR_METER); CHECK(parse_tempo(token[2], ps), MERR_TEMPO); CHECK(parse_pattern(token[3], ps), MERR_PATTERN); CHECK(parse_volume(token[4], ps), MERR_VOLUME); } if(!ps->pattern) { /* For parsed parts default to emphasize every first beat. */ CHECK(ps->pattern = mem_allocate(ps->beats_per_bar), MERR_OOM); memset(ps->pattern, 'x', ps->beats_per_bar); ps->pattern[0] = 'X'; } part_add(ps); return; /* all good */ /* Remove part after some error. */ parse_part_revert: rb->snprintf(buffer, sizeof(buffer), "ERR %u @line %u", errcode, num); rb->splash(2*HZ, buffer); ++bad_parts; mem_reset(); } #undef CHECK static void step_back(void) { beating = false; beat = 0; if(bar) { /* Endless parts only know position 0 to step to. */ if(part->bars) --bar; else bar = 0; } else if(part->prev) { part = part->prev; /* This will jump to bar 0 for endless parts. */ bar = positive(part->bars)-1; tweak_volume(part->volume); } /* Always calculate period for acceleration. */ calc_period(); minitick = period; } static void step_forw(void) { beating = false; /* Stepping forward in endless part always goes to the next one, if any. */ if(part->bars == 0 || bar+1 == part->bars) { if(part->next) { /* Advanced one part. */ part = part->next; bar = 0; beat = 0; tweak_volume(part->volume); } } else ++bar; /* Always calculate period for acceleration. */ calc_period(); minitick = period; } static void tap(void) { struct part *ps = part; /* Each tap resets the position. */ beat = 0; bar = 0; if(tap_count == 0 || tap_time < tap_count) tap_time = 0; else { if(tap_time > 0) { /* Could use fixed point math and rounding, even. */ ps->bpm = 60*timerfreq_div*tap_count/tap_time; if(ps->bpm > 400) ps->bpm = 400; } tap_timeout = (tap_count+2)*tap_time/tap_count; } tap_count++; minitick = 0; /* sync tock to tapping */ reset_tap = false; play_ticktock(); } enum plugin_status plugin_start(const void* file) { int button; static int last_button = BUTTON_NONE; bool common_action; atexit(cleanup); mem_init(); if(MET_IS_PLAYING) MET_PLAY_STOP; /* stop audio IS */ prepare_buffers(); #if INPUT_SRC_CAPS != 0 /* Select playback */ rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); #endif rb->pcm_set_frequency(SAMPR_44); if(file) { parts = 0; bad_parts = 0; fd = rb->open(file, O_RDONLY); if(fd >= 0) { unsigned int linenum = 0; /* Crazyness, allocating line buffer depending on free memory. */ linebuf_size = mem_end - mem_free_region > 32*1024 ? 1024 : ( mem_end - mem_free_region > 16*1024 ? 256 : 128 ); if(!(linebuf = mem_allocate(linebuf_size))) return PLUGIN_ERROR; /* I'm assuming that read_line always terminates. */ while(rb->read_line(fd, linebuf, linebuf_size) > 0) { parse_part(linebuf, ++linenum); } } rb->close(fd); if(bad_parts) { rb->snprintf(buffer, sizeof(buffer), "%u bad parts", bad_parts); rb->splash(2*HZ, buffer); } if(!parts) { rb->splash(2*HZ, "Got no parts. Bye!"); return PLUGIN_OK; } } /* If no parts given, start in simple metronome mode. */ if(!parts) { /* Just checking the early bailout here. */ struct part *ps = mem_allocate(sizeof(struct part)); if(!ps) return PLUGIN_ERROR; part_init(ps); part_add(ps); track_mode = false; } else track_mode = true; part = part_list; tweak_volume(part->volume); calc_period(); draw_display(); /* main loop */ while(true) { reset_tap = true; button = pluginlib_getaction( TIMEOUT_NOBLOCK, plugin_contexts , PLA_ARRAY_COUNT ); if(sound_trigger) { sound_trigger = false; play_ticktock(); /* Draws display before playback. */ } common_action = false; if(track_mode) { switch(button) { case METRONOME_START: if(sound_paused) metronome_unpause(); else metronome_pause(); break; case METRONOME_PAUSE: if(!sound_paused) metronome_pause(); break; case METRONOME_LEFT: case METRONOME_LEFT_REP: step_back(); trigger_display(0); break; case METRONOME_RIGHT: case METRONOME_RIGHT_REP: step_forw(); trigger_display(0); break; default: common_action = true; } } else { switch(button) { case METRONOME_PAUSE: if(!sound_paused) metronome_pause(); break; case METRONOME_PLAY: if(sound_paused) metronome_unpause(); break; case METRONOME_TAP: if(last_button != METRONOME_PLAY) { if(sound_paused) metronome_unpause(); tap(); } break; case METRONOME_LEFT: bpm_step_counter = 0; /* fallthrough */ case METRONOME_LEFT_REP: change_bpm(-1); break; case METRONOME_RIGHT: bpm_step_counter = 0; /* fallthrough */ case METRONOME_RIGHT_REP: change_bpm(1); break; #ifdef MET_SYNC case METRONOME_SYNC: minitick = period; break; #endif default: common_action = true; } } if(common_action) switch(button) { case METRONOME_QUIT: /* get out of here */ return PLUGIN_OK; case METRONOME_VOL_UP: case METRONOME_VOL_UP_REP: change_volume(1); trigger_display(0); break; case METRONOME_VOL_DOWN: case METRONOME_VOL_DOWN_REP: change_volume(-1); trigger_display(0); break; default: exit_on_usb(button); reset_tap = false; break; } if(button) last_button = button; if(reset_tap) tap_count = 0; /* If there was some action, display drawing is still needed. This _might_ disturb audio on slow machines, but then, you could just stop pressing buttons, then;-) */ if(display_trigger) { display_trigger = false; draw_display(); } /* This determines the accuracy of the metronome with SWCODEC ... the scheduler decides when we are allowed to play. */ rb->yield(); } }