{"id":1849,"date":"2015-12-06T21:51:11","date_gmt":"2015-12-06T18:51:11","guid":{"rendered":"http:\/\/www.avray.ru\/?page_id=1849"},"modified":"2016-09-10T16:39:48","modified_gmt":"2016-09-10T13:39:48","slug":"playing-yrg-rsf-files-from-sd-card-with-emulator","status":"publish","type":"page","link":"https:\/\/www.avray.ru\/ru\/playing-yrg-rsf-files-from-sd-card-with-emulator\/","title":{"rendered":"\u041f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u043d\u0438\u0435 YRG, RSF \u0444\u0430\u0439\u043b\u043e\u0432 \u0441 SD \u043a\u0430\u0440\u0442\u044b (\u0441 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c)"},"content":{"rendered":"<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 Arduino \u0441\u043a\u0435\u0442\u0447 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c YRG \u0438 RSF \u0444\u0430\u0439\u043b\u044b \u0438\u0437 \u043a\u043e\u0440\u043d\u044f SD \u043a\u0430\u0440\u0442\u044b \u043d\u0430 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0435 \u0441 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u0430\u0439\u0442\u0430 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435. (\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d 12.12.2015 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 RSFv3)<\/p>\n<p><strong>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/strong><\/p>\n<p>\u041f\u0438\u043d\u044b \u043d\u0430 Arduino:<\/p>\n<p>&nbsp;<\/p>\n<p>1 (TX pin) -&gt; RX pin \u043d\u0430 Atmega8<\/p>\n<p><strong>SD \u043a\u0430\u0440\u0442\u0430:<\/strong><\/p>\n<p>MOSI \u2014 11, MISO \u2014 12, CLK(SCK) \u2014 13, CS \u2014 4<\/p>\n<p>&nbsp;<\/p>\n<pre>#include &lt;SPI.h&gt;\r\n#include &lt;SD.h&gt;\r\n\r\nconst int CS_Pin = 4;\r\n\r\nFile dataFile;\r\nFile entry,root;\r\n\r\nvoid setup()\r\n{\r\n  pinMode(CS_Pin, OUTPUT);\r\n\r\n  \/\/ see if the card is present and can be initialized:\r\n  if (!SD.begin(CS_Pin)) return;\r\n\r\n  root = SD.open(\"\/\",FILE_READ);  \r\n\r\n  Serial.begin(57600);\r\n}\r\n\r\n\r\n#define BUF_MAX 16*15\r\nstatic byte buf[BUF_MAX];\r\nstatic byte buf2[29];\r\nunsigned long t;\r\n\r\n\r\n\/\/\/ PLAY YRG FILE ==============================\r\nvoid play_yrg()\r\n{\r\n   byte regbuf[28];\r\n   byte bframes;\r\n   \r\n   while(dataFile.available())\r\n   {\r\n     \/\/ read 16 x16 regs\r\n     bframes = dataFile.read(buf,BUF_MAX)\/16;\r\n     for (byte frame = 0; frame &lt; bframes; frame++)\r\n     {\r\n       \/\/ send diff registers from current frame\r\n       byte buf_p = 0;\r\n       for (byte reg = 0; reg &lt; 14; reg++)\r\n       {\r\n           if (reg == 13 &amp;&amp; buf[frame*16+reg]==255) break;\r\n           if(reg == 13 || buf2[reg] != buf[frame*16+reg]) {\r\n             regbuf[buf_p++] = reg;\r\n             regbuf[buf_p++] = buf[frame*16+reg];\r\n           }\r\n       }\r\n       Serial.write(regbuf,buf_p);\r\n       memcpy(buf2,&amp;buf[frame*16],14);\r\n       \/\/delay(20);\r\n       while(millis() - t &lt; 20); \r\n       t = millis();\r\n     }\r\n   }\r\n}\r\n\r\n\/\/\/ PLAY RSF FILE ==============================\r\nvoid play_rsf()\r\n{\r\n   \/\/unsigned long frames, loopframe,curframe=0;\r\n   word freq, offset;\r\n   byte val, zeroes, ptr = 0, count, mask2, mask1, delay_time, skip;\r\n   \r\n   if( dataFile.read(buf,4) &lt;= 0 ) return; \/\/ short file\r\n\r\n   if(buf[0] != 'R' || buf[1] != 'S' || buf[2] != 'F') return; \/\/not RSF\r\n   \r\n   switch(buf[3])\r\n   { \/\/ reading RSF HEADER v3 only supported!\r\n     case 3: \/\/ RSF ver.3\r\n           if( dataFile.read(buf,14) == 0 ) return; \/\/ short file\r\n           memcpy(&amp;freq,&amp;buf[0],sizeof(word));\r\n           memcpy(&amp;offset,&amp;buf[2],sizeof(word));\r\n           \/\/memcpy(&amp;frames,&amp;buf[4],sizeof(unsigned long));\r\n           \/\/memcpy(&amp;loopframe,&amp;buf[8],sizeof(unsigned long));\r\n           break;\r\n     default:\r\n           return;\r\n   }\r\n\r\n   if( freq &gt; 1000 ) return; \/\/ frequency is too fast\r\n   \r\n   delay_time = 1000 \/ freq;\r\n  \r\n   \/\/ skip text info\r\n   dataFile.seek(offset);\r\n\r\n   \/\/ play song data\r\n   if( (count = dataFile.read(buf,BUF_MAX)) &lt;= 0 ) return;\r\n\r\n   for(;;) {   \r\n         if(ptr &gt; count&gt;&gt;1)\r\n         { \/\/ half buffer is already played move it and load more\r\n           byte msize = count - ptr;\r\n           memmove(buf,&amp;buf[ptr], msize);\r\n           if( (count = dataFile.read(&amp;buf[msize],ptr)) &lt;= 0 ) return;\r\n           count += msize;\r\n           ptr = 0;\r\n         }\r\n         val = buf[ptr++];\r\n         skip = 1;       \r\n         switch(val)\r\n         {\r\n           case 255:\r\n               break;\r\n           case 254:\r\n               skip = buf[ptr++];\r\n               if(ptr &gt;= count) return;\r\n               break;\r\n           default:\r\n               mask2 = val;\r\n               mask1 = buf[ptr++];\r\n               byte reg = 0, reg_p = 0;\r\n               while( mask1 != 0)\r\n               {\r\n                   if(mask1 &amp; 1) {\r\n                     buf2[reg_p++] = reg;\r\n                     buf2[reg_p++] = buf[ptr++];\r\n                   }\r\n                   mask1 &gt;&gt;= 1;\r\n                   reg++;\r\n               }\r\n               reg = 8;\r\n               while(mask2 != 0)\r\n               {\r\n                   if(mask2 &amp; 1) {\r\n                     buf2[reg_p++] = reg;\r\n                     buf2[reg_p++] = buf[ptr++];\r\n                   }\r\n                   mask2 &gt;&gt;= 1;\r\n                   reg++;\r\n               }\r\n               Serial.write(buf2,reg_p);\r\n         }             \r\n         \/\/curframe += skip;\r\n         while(millis() - t &lt; delay_time * skip); \/\/ delay\r\n         t = millis();\r\n   }\r\n}\r\n\r\nvoid loop()\r\n{\r\n byte file_type;\r\n  \/\/ reset AY\r\n memset(buf2,0,29);\r\n buf2[0] = 255;\r\n for(byte i = 0; i &lt; 14; i++) buf2[i*2+1]=i;\r\n Serial.write(buf2,29);\r\n memset(buf2,0,29);\r\n\r\n for(;;) { \/\/ find file\r\n    file_type = 0;\r\n    if(entry) entry.close();\r\n    entry = root.openNextFile();\r\n    if(!entry) { \/\/ end of files on SD\r\n       root.rewindDirectory();\r\n       entry = root.openNextFile();\r\n    }\r\n    \r\n    if(entry.isDirectory()) continue;\r\n\r\n    if(strcasestr(entry.name(),\".yrg\")) {\r\n      file_type = 1;\r\n      break;\r\n    }\r\n    if(strcasestr(entry.name(),\".rsf\")) {\r\n      file_type = 2;\r\n      break;\r\n    }\r\n }\r\n\r\n dataFile = SD.open(entry.name(),FILE_READ);\r\n\r\n t = millis();\r\n \r\n switch(file_type)\r\n {\r\n    case 1:\r\n        play_yrg();\r\n        break;\r\n    case 2:\r\n        play_rsf();\r\n        break;\r\n }\r\n\r\n dataFile.close();\r\n entry.close();\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h2>\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043a\u0435\u0442\u0447, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 SdFat<\/h2>\n<pre>#include &lt;SdFat.h&gt;\r\n#undef USE_ARDUINO_SPI_LIBRARY\r\n#define USE_ARDUINO_SPI_LIBRARY 0\r\n\r\n#define CS_Pin 4\r\n#define BAUD_RATE 57600\r\n#define BAUD_PRESCALE (((F_CPU\/(BAUD_RATE*16UL)))-1)\r\n\r\nSdFat SD;\r\nSdFile dataFile;\r\n\r\nvoid serialwrite(byte* buf,byte bsize)\r\n{\r\n  for(byte i=0 ; i &lt; bsize; i++)\r\n  {\r\n    while ((UCSR0A &amp; (1 &lt;&lt; UDRE0)) == 0) {}; \/\/ Do nothing until UDR is ready for more data to be written to it\r\n    UDR0 = buf[i]; \/\/ Send out the byte value in the variable \"ByteToSend\"\r\n  }\r\n}\r\n\r\n\r\nvoid setup()\r\n{\r\n  if (!SD.begin(CS_Pin, SPI_FULL_SPEED)) return;\/\/SD.initErrorHalt();\r\n\r\n  \/\/ initialize serial interface\r\n  UCSR0B |= (1&lt;&lt;RXEN0)  | (1&lt;&lt;TXEN0);\r\n  UCSR0C |= (1&lt;&lt;UCSZ00) | (1&lt;&lt;UCSZ01);\r\n  UBRR0H = BAUD_PRESCALE &gt;&gt; 8;\r\n  UBRR0L = BAUD_PRESCALE;\r\n}\r\n\r\n#define BUF_MAX 16*5\r\n\r\nstatic byte buf[BUF_MAX];\r\nstatic byte buf2[29];\r\nstatic unsigned long t;\r\n\r\n\r\n\/\/\/ PLAY YRG FILE ==============================\r\nvoid play_yrg()\r\n{\r\n   byte regbuf[28];\r\n   byte bframes;\r\n   \r\n   while((bframes = dataFile.read(buf,BUF_MAX)\/16) &gt; 0)\r\n   {\r\n     for (byte frame = 0; frame &lt; bframes; frame++)\r\n     {\r\n       \/\/ send diff registers from current frame\r\n       byte buf_p = 0;\r\n       for (byte reg = 0; reg &lt; 14; reg++)\r\n       {\r\n           if (reg == 13 &amp;&amp; buf[frame*16+reg]==255) break;\r\n           if(reg == 13 || buf2[reg] != buf[frame*16+reg]) {\r\n             regbuf[buf_p++] = reg;\r\n             regbuf[buf_p++] = buf[frame*16+reg];\r\n           }\r\n       }\r\n       serialwrite(regbuf,buf_p);\r\n       memcpy(buf2,&amp;buf[frame*16],14);\r\n       \r\n       while(millis() - t &lt; 20); \/\/delay(20);\r\n       t = millis();\r\n     }\r\n   }\r\n}\r\n\r\n\/\/\/ PLAY RSF FILE ==============================\r\nvoid play_rsf()\r\n{\r\n   \/\/unsigned long frames, loopframe,curframe=0;\r\n   word freq, offset;\r\n   byte val, ptr = 0, count, mask2, mask1, delay_time, skip;\r\n   \r\n   if( dataFile.read(buf,4) &lt;= 0 ) return; \/\/ short file\r\n\r\n   if(buf[0] != 'R' || buf[1] != 'S' || buf[2] != 'F') return; \/\/not RSF\r\n   \r\n   switch(buf[3])\r\n   { \/\/ reading RSF HEADER v3 only supported!\r\n     case 3: \/\/ RSF ver.3\r\n           if( dataFile.read(buf,14) == 0 ) return; \/\/ short file\r\n           memcpy(&amp;freq,&amp;buf[0],sizeof(word));\r\n           memcpy(&amp;offset,&amp;buf[2],sizeof(word));\r\n           \/\/memcpy(&amp;frames,&amp;buf[4],sizeof(unsigned long));\r\n           \/\/memcpy(&amp;loopframe,&amp;buf[8],sizeof(unsigned long));\r\n           break;\r\n     default:\r\n           return;\r\n   }\r\n\r\n   if( freq &gt; 1000 ) return; \/\/ frequency is too fast\r\n   \r\n   delay_time = 1000 \/ freq;\r\n  \r\n   \/\/ skip text info\r\n   dataFile.seekSet(offset);\r\n\r\n   \/\/ play song data\r\n   if( (count = dataFile.read(buf,BUF_MAX)) &lt;= 0 ) return;\r\n\r\n   for(;;) {   \r\n         if(ptr &gt; count&gt;&gt;1)\r\n         { \/\/ half buffer is already played move it and load more\r\n           byte msize = count - ptr;\r\n           memmove(buf,&amp;buf[ptr], msize);\r\n           if( (count = dataFile.read(&amp;buf[msize],ptr)) &lt;= 0 ) return;\r\n           count += msize;\r\n           ptr = 0;\r\n         }\r\n         val = buf[ptr++];\r\n         skip = 1;       \r\n         switch(val)\r\n         {\r\n           case 255:\r\n               break;\r\n           case 254:\r\n               skip = buf[ptr++];\r\n               break;\r\n           default:\r\n               mask2 = val;\r\n               mask1 = buf[ptr++];\r\n               byte reg = 0, reg_p = 0;\r\n               while( mask1 != 0)\r\n               {\r\n                   if(mask1 &amp; 1) {\r\n                     buf2[reg_p++] = reg;\r\n                     buf2[reg_p++] = buf[ptr++];\r\n                   }\r\n                   mask1 &gt;&gt;= 1;\r\n                   reg++;\r\n               }\r\n               reg = 8;\r\n               while(mask2 != 0)\r\n               {\r\n                   if(mask2 &amp; 1) {\r\n                     buf2[reg_p++] = reg;\r\n                     buf2[reg_p++] = buf[ptr++];\r\n                   }\r\n                   mask2 &gt;&gt;= 1;\r\n                   reg++;\r\n               }\r\n               serialwrite(buf2,reg_p);\r\n         }             \r\n\r\n         \/\/curframe += skip;\r\n         while(millis() - t &lt; delay_time * skip); \/\/ delay\r\n         t = millis();\r\n   }\r\n}\r\n\r\n\/\/\/=====================================================\r\nvoid loop()\r\n{\r\n byte file_type;\r\n char fname[12]; \/\/ using short filenames\r\n \r\n  \/\/ reset AY\r\n memset(buf2,0,29);\r\n buf2[0] = 255;\r\n for(byte i = 0; i &lt; 14; i++) buf2[i*2+1]=i;\r\n serialwrite(buf2,29);\r\n memset(buf2,0,29);\r\n\r\n for(;;) { \/\/ find file\r\n    file_type = 0;\r\n\r\n    if(!dataFile.openNext(SD.vwd(), O_READ)) dataFile.openRoot(dataFile.volume()); \/\/ end of files on SD\r\n    \r\n    if(dataFile.isDir()) {\r\n      dataFile.close();\r\n      continue;\r\n    }\r\n    \r\n    dataFile.getFilename(fname);\r\n    \r\n    if(strcasestr(fname,\".yrg\")) {\r\n      file_type = 1;\r\n      break;\r\n    }\r\n    if(strcasestr(fname,\".rsf\")) {\r\n      file_type = 2;\r\n      break;\r\n    }\r\n }\r\n\r\n t = millis();\r\n \r\n switch(file_type)\r\n {\r\n    case 1:\r\n        play_yrg();\r\n        break;\r\n    case 2:\r\n        play_rsf();\r\n        break;\r\n }\r\n\r\n dataFile.close();\r\n}<\/pre>\n<p style=\"text-align: center;\"><a href=\"http:\/\/www.avray.ru\/wp-content\/uploads\/2016\/09\/connect.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2124\" src=\"http:\/\/www.avray.ru\/wp-content\/uploads\/2016\/09\/connect.png\" alt=\"connect\" width=\"1402\" height=\"1214\" srcset=\"https:\/\/www.avray.ru\/wp-content\/uploads\/2016\/09\/connect.png 1402w, https:\/\/www.avray.ru\/wp-content\/uploads\/2016\/09\/connect-300x260.png 300w, https:\/\/www.avray.ru\/wp-content\/uploads\/2016\/09\/connect-768x665.png 768w, https:\/\/www.avray.ru\/wp-content\/uploads\/2016\/09\/connect-1024x887.png 1024w\" sizes=\"auto, (max-width: 1402px) 100vw, 1402px\" \/><\/a><\/p>\n<p style=\"text-align: center;\">[ad name=&#187;HTML&#187;]<\/p>\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 Arduino \u0441\u043a\u0435\u0442\u0447 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c YRG \u0438 RSF \u0444\u0430\u0439\u043b\u044b \u0438\u0437 \u043a\u043e\u0440\u043d\u044f SD \u043a\u0430\u0440\u0442\u044b \u043d\u0430 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0435 \u0441 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u0430\u0439\u0442\u0430 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435. (\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d 12.12.2015 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 RSFv3) \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435: \u041f\u0438\u043d\u044b \u043d\u0430 Arduino: &nbsp; 1 (TX pin) -&gt; RX pin \u043d\u0430 Atmega8 SD \u043a\u0430\u0440\u0442\u0430: MOSI \u2014 11, MISO \u2014 12, CLK(SCK) \u2014 13, CS \u2014 4 &nbsp; [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"closed","template":"page-fullwidth.php","meta":{"footnotes":""},"class_list":["post-1849","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/pages\/1849","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/comments?post=1849"}],"version-history":[{"count":0,"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/pages\/1849\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.avray.ru\/ru\/wp-json\/wp\/v2\/media?parent=1849"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}