├── .DS_Store ├── .gitmodules ├── README.md ├── bootstrap ├── css │ ├── bootstrap-responsive.css │ ├── bootstrap-responsive.min.css │ ├── bootstrap.css │ └── bootstrap.min.css ├── img │ ├── glyphicons-halflings-white.png │ └── glyphicons-halflings.png └── js │ ├── bootstrap.js │ └── bootstrap.min.js ├── index.html ├── js ├── jquery-1.8.1.min.js └── js-snes-player.js ├── notes ├── sink.js ├── snes_spc-0.9.0 ├── .DS_Store ├── changes.txt ├── demo │ ├── benchmark.c │ ├── comm.c │ ├── demo_util.c │ ├── demo_util.h │ ├── play_spc.c │ ├── save_state.c │ ├── trim_spc.c │ ├── wave_writer.c │ └── wave_writer.h ├── fast_dsp │ ├── SPC_DSP.cpp │ └── SPC_DSP.h ├── license.txt ├── readme.txt ├── snes_spc.js ├── snes_spc.txt └── snes_spc │ ├── .DS_Store │ ├── SNES_SPC.cpp │ ├── SNES_SPC.h │ ├── SNES_SPC_misc.cpp │ ├── SNES_SPC_state.cpp │ ├── SPC_CPU.h │ ├── SPC_DSP.cpp │ ├── SPC_DSP.h │ ├── SPC_Filter.cpp │ ├── SPC_Filter.h │ ├── blargg_common.h │ ├── blargg_config.h │ ├── blargg_endian.h │ ├── blargg_source.h │ ├── dsp.cpp │ ├── dsp.h │ ├── spc.cpp │ └── spc.h └── songs ├── .DS_Store ├── Super Mario World ├── .DS_Store ├── smw-01.spc ├── smw-01.spc.json ├── smw-02.spc ├── smw-02.spc.json ├── smw-03.spc ├── smw-03.spc.json ├── smw-04.spc ├── smw-04.spc.json ├── smw-05.spc ├── smw-05.spc.json ├── smw-06.spc ├── smw-06.spc.json ├── smw-07.spc ├── smw-07.spc.json ├── smw-08.spc ├── smw-08.spc.json ├── smw-09.spc ├── smw-09.spc.json ├── smw-10a.spc ├── smw-10a.spc.json ├── smw-10b.spc ├── smw-10b.spc.json ├── smw-11a.spc ├── smw-11a.spc.json ├── smw-11b.spc ├── smw-11b.spc.json ├── smw-11c.spc ├── smw-11c.spc.json ├── smw-11d.spc ├── smw-11d.spc.json ├── smw-12a.spc ├── smw-12a.spc.json ├── smw-12b.spc ├── smw-12b.spc.json ├── smw-12c.spc ├── smw-12c.spc.json ├── smw-12d.spc ├── smw-12d.spc.json ├── smw-13a.spc ├── smw-13a.spc.json ├── smw-13b.spc ├── smw-13b.spc.json ├── smw-13c.spc ├── smw-13c.spc.json ├── smw-13d.spc ├── smw-13d.spc.json ├── smw-14a.spc ├── smw-14a.spc.json ├── smw-14b.spc ├── smw-14b.spc.json ├── smw-14c.spc ├── smw-14c.spc.json ├── smw-14d.spc ├── smw-14d.spc.json ├── smw-15a.spc ├── smw-15a.spc.json ├── smw-15b.spc ├── smw-15b.spc.json ├── smw-16a.spc ├── smw-16a.spc.json ├── smw-16b.spc ├── smw-16b.spc.json ├── smw-17a.spc ├── smw-17a.spc.json ├── smw-17b.spc ├── smw-17b.spc.json ├── smw-17c.spc ├── smw-17c.spc.json ├── smw-17d.spc ├── smw-17d.spc.json ├── smw-18a.spc ├── smw-18a.spc.json ├── smw-18b.spc ├── smw-18b.spc.json ├── smw-18c.spc ├── smw-18c.spc.json ├── smw-18d.spc ├── smw-18d.spc.json ├── smw-19a.spc ├── smw-19a.spc.json ├── smw-19b.spc ├── smw-19b.spc.json ├── smw-20.spc ├── smw-20.spc.json ├── smw-21a.spc ├── smw-21a.spc.json ├── smw-21b.spc ├── smw-21b.spc.json ├── smw-22.spc ├── smw-22.spc.json ├── smw-23.spc ├── smw-23.spc.json ├── smw-24.spc ├── smw-24.spc.json ├── smw-25.spc ├── smw-25.spc.json ├── smw-26.spc ├── smw-26.spc.json ├── smw-27.spc ├── smw-27.spc.json ├── smw-28.spc ├── smw-28.spc.json ├── smw-29.spc ├── smw-29.spc.json ├── smw-30a.spc ├── smw-30a.spc.json ├── smw-30b.spc ├── smw-30b.spc.json ├── smw-30c.spc ├── smw-30c.spc.json ├── smw-30d.spc ├── smw-30d.spc.json ├── smw-31a.spc ├── smw-31a.spc.json ├── smw-31b.spc ├── smw-31b.spc.json ├── smw-32.spc ├── smw-32.spc.json ├── smw-33.spc ├── smw-33.spc.json ├── smw-34.spc ├── smw-34.spc.json ├── smw-35.spc ├── smw-35.spc.json ├── smw-36.spc ├── smw-36.spc.json ├── smw-37a.spc ├── smw-37a.spc.json ├── smw-37b.spc ├── smw-37b.spc.json ├── smw-s01.spc └── smw-s01.spc.json ├── Zelda ├── .DS_Store ├── loz3-01.spc ├── loz3-01.spc.json ├── loz3-02.spc ├── loz3-02.spc.json ├── loz3-03.spc ├── loz3-03.spc.json ├── loz3-04a.spc ├── loz3-04a.spc.json ├── loz3-04b.spc ├── loz3-04b.spc.json ├── loz3-05a.spc ├── loz3-05a.spc.json ├── loz3-05b.spc ├── loz3-05b.spc.json ├── loz3-06.spc ├── loz3-06.spc.json ├── loz3-07.spc ├── loz3-07.spc.json ├── loz3-08.spc ├── loz3-08.spc.json ├── loz3-09.spc ├── loz3-09.spc.json ├── loz3-10.spc ├── loz3-10.spc.json ├── loz3-11.spc ├── loz3-11.spc.json ├── loz3-12.spc ├── loz3-12.spc.json ├── loz3-13.spc ├── loz3-13.spc.json ├── loz3-14.spc ├── loz3-14.spc.json ├── loz3-15.spc ├── loz3-15.spc.json ├── loz3-16.spc ├── loz3-16.spc.json ├── loz3-17a.spc ├── loz3-17a.spc.json ├── loz3-17b.spc ├── loz3-17b.spc.json ├── loz3-18.spc ├── loz3-18.spc.json ├── loz3-19.spc ├── loz3-19.spc.json ├── loz3-20.spc ├── loz3-20.spc.json ├── loz3-21.spc ├── loz3-21.spc.json ├── loz3-22a.spc ├── loz3-22a.spc.json ├── loz3-22b.spc ├── loz3-22b.spc.json ├── loz3-23.spc ├── loz3-23.spc.json ├── loz3-24.spc ├── loz3-24.spc.json ├── loz3-25.spc ├── loz3-25.spc.json ├── loz3-26.spc ├── loz3-26.spc.json ├── loz3-27.spc ├── loz3-27.spc.json ├── loz3-28.spc ├── loz3-28.spc.json ├── loz3-29.spc ├── loz3-29.spc.json ├── loz3-30.spc ├── loz3-30.spc.json ├── loz3-31.spc ├── loz3-31.spc.json ├── loz3-b01.spc ├── loz3-b01.spc.json ├── loz3-b02.spc ├── loz3-b02.spc.json ├── loz3-b03.spc ├── loz3-b03.spc.json ├── loz3-s01.spc ├── loz3-s01.spc.json ├── loz3-s02.spc ├── loz3-s02.spc.json ├── loz3-s03.spc ├── loz3-s03.spc.json ├── loz3-s04.spc ├── loz3-s04.spc.json ├── loz3-s05.spc ├── loz3-s05.spc.json ├── loz3-s06.spc ├── loz3-s06.spc.json ├── loz3-s07.spc ├── loz3-s07.spc.json ├── loz3-s08a.spc ├── loz3-s08a.spc.json ├── loz3-s08b.spc ├── loz3-s08b.spc.json ├── loz3-s09.spc ├── loz3-s09.spc.json ├── loz3-s10.spc ├── loz3-s10.spc.json ├── loz3-s11.spc └── loz3-s11.spc.json ├── index.json ├── index.php └── script.sh /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/.DS_Store -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sink.js"] 2 | path = sink.js 3 | url = https://github.com/jussi-kalliokoski/sink.js/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | js-snes-player 2 | ============== 3 | 4 | This is a fork of MrRio's original 5 | 6 | 7 | [Demo](http://cosinusoidally.github.com/js-snes-player/) 8 | ---- 9 | 10 | A prototype for a HTML5 audio player that can emulate the Nintendo SNES. 11 | 12 | How it was done: 13 | 14 | 1. SPC files are converted to JSON so they can be loaded in 15 | 2. The SNES_SPC library (written in C++) is compiled to LLVM, which in turn is compiled to JavaScript, thanks to Emscripten 16 | 3. The SPC file is written to a virtual memory pointer and handed to the C++ library 17 | 4. The library generates the raw audio which is pushed on to the memory heap 18 | 5. We read the audio data from the heap, and push that on to the new HTML5 Web Audio API 19 | 20 | Status 21 | ------ 22 | 23 | There's a few performance issues, but there's a basic mono stream working :) 24 | 25 | -------------------------------------------------------------------------------- /bootstrap/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.1.0 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade.in{top:auto}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#555;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | js-snes-player 7 | 8 | 9 | 10 | 11 | 12 | 13 | 23 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 65 | 66 |
67 | 68 |

Play SNES Tunes in Your Browser

69 |

This is a bodged fork of MrRio's original. See https://github.com/MrRio/js-snes-player . You will need to reload the page after playing each tune

70 |

The SNES audio chip emulation is happening in your browser, in JavaScript. How cool is that?

71 |

Sometimes a browser refresh improves performance

72 | 73 |
74 |
75 |
76 | 77 |
78 | 79 |
80 | 81 |
82 | 83 | 84 |
85 |
86 | Fork me on GitHub 87 | 88 | 89 | -------------------------------------------------------------------------------- /js/js-snes-player.js: -------------------------------------------------------------------------------- 1 | /* js-snes-player - a HTML SNES SPC file player 2 | (c) 2012 James Hall 3 | */ 4 | 5 | 6 | bufferSize = 16384*2; 7 | 8 | var jsSNESPlayer = function() { 9 | 10 | 11 | function error(str) { 12 | 13 | if (str != '(null)') { 14 | alert(str); 15 | } 16 | } 17 | 18 | var proxy; 19 | var proxy; 20 | var first 21 | 22 | var play = function(SongData) { 23 | //run(); 24 | //console.log(window); 25 | 26 | console.log('Make new SPC instance...'); 27 | var snes_spc = _spc_new(); 28 | 29 | console.log('Load filter...'); 30 | var filter = _spc_filter_new(); 31 | if (!snes_spc || !filter) { 32 | alert('Failed to load'); 33 | } else { 34 | // Load SPC file into memory 35 | // @TODO: Actually load the file in 36 | 37 | 38 | var spc = allocate(SongData, 'i8', ALLOC_STACK); 39 | 40 | console.log('Load SPC data into pointer...'); 41 | 42 | var spc_size = SongData.length; 43 | 44 | console.log('SPC size is ' + spc_size); 45 | 46 | console.log('Loading SPC'); 47 | var load = _spc_load_spc(snes_spc, spc, spc_size); 48 | console.log('SPC file loaded'); 49 | 50 | _spc_set_tempo(snes_spc, 320); 51 | _spc_set_output(); 52 | _spc_clear_echo(snes_spc); 53 | _spc_filter_clear(filter); 54 | 55 | console.log('Creating audio sink...'); 56 | buf = allocate(new Uint8Array(1e6), 'i8', ALLOC_STACK); 57 | myaudioprocess= function(buffer, channelCount){ 58 | var retval = _spc_play(snes_spc, bufferSize/2 , buf); 59 | _spc_filter_run(filter, buf, bufferSize); 60 | 61 | for (i = 0; i < bufferSize; i =i+2) { 62 | 63 | // Take a mono stream 64 | if ((i - 1) % 2 == 0) { 65 | buffer[i/2] = HEAP8[i + buf] / 120; 66 | 67 | } else { 68 | buffer[i/2] = HEAP8[i + buf - 1] / 120; 69 | 70 | } 71 | } 72 | }; 73 | 74 | } 75 | 76 | context = new AudioContext(); 77 | 78 | 79 | audioNode = context.createScriptProcessor(bufferSize/2, 0, 1); 80 | 81 | audioNode.onaudioprocess = function(audioProcessingEvent) { 82 | 83 | // The output buffer contains the samples that will be modified and played 84 | outputBuffer = audioProcessingEvent.outputBuffer; 85 | for (var channel = 0; channel < outputBuffer.numberOfChannels; channel++) { 86 | outData = outputBuffer.getChannelData(channel); 87 | 88 | 89 | myaudioprocess(outData,1); 90 | }} 91 | 92 | audioNode.connect(context.destination); 93 | } 94 | 95 | 96 | return { 97 | init: function() { 98 | $.get('songs/index.json', function(response) { 99 | response = $.parseJSON(response); 100 | $.each(response, function() { 101 | $('.song-selector').append(''); 102 | }); 103 | }); 104 | 105 | $(document).ready(function() { 106 | $('.js-snes-start').click(function() { 107 | console.log('Start playing'); 108 | 109 | var song = $('.song-selector').val(); 110 | if (song == null) { 111 | alert('You need to select a song first silly!'); 112 | } else { 113 | $.get('songs/' + song + '.json', function(response) { 114 | SongData=response; 115 | response = $.parseJSON(response); 116 | play(response); 117 | }); 118 | } 119 | 120 | }); 121 | 122 | $('.js-snes-stop').click(function() { 123 | console.log(proxy); 124 | proxy.parentSink.kill(); 125 | 126 | }) 127 | }); 128 | 129 | } 130 | } 131 | 132 | }(); 133 | 134 | //setTimeout(function() { 135 | jsSNESPlayer.init(); 136 | //}, 2000); 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /notes: -------------------------------------------------------------------------------- 1 | These are my notes (Liam Wilson). I gave MrRio's js-snes-player a go, but it failed to work in both Firefox 31 and Chrome 36.0.1985.143.[3~ 2 | 3 | Error messages: 4 | 5 | Firefox: Error: No audio sink available. sink.js:412 6 | Chrome: Uncaught [object Object] sink.js:35 7 | 8 | Seems to be using a project called sink.js to play back audio. sink.js seems to be broken in both FF and Chrome. 9 | 10 | I'll concentrate on Firefox for now. Strangely it fails in different places in FF and Chrome. 11 | 12 | Looking at the code: 13 | 14 | Emscripten generated code in snes_spc-0.9.0/snes_spc.js . This looks like old Emscripten code (pre-asm.js ). From the comments at the top: 15 | 16 | // Note: Some Emscripten settings will significantly limit the speed of the generated code. 17 | // Note: Some Emscripten settings may limit the speed of the generated code. 18 | // TODO: " u s e s t r i c t "; 19 | 20 | Last commit by MrRio is Aug 2012. This explains it (that's about 6 months before asm.js was available). Will need to regenerate the code at some point. Shouldn't affect fixing the audio bug. 21 | 22 | Web Audio was also a mess in 2012 (and still is in 2014 really). This probably explains why sink.js just fails. 23 | 24 | Looks like last commit to sink.js was https://github.com/jussi-kalliokoski/sink.js/commits/master in October 2012. Maybe abandoned. 25 | 26 | Anyway, back to the audio bug... 27 | 28 | Next it loads js/js-snes-player.js 29 | 30 | Module pattern. jsSNESPlayer created then init function called. init sets up a bunch of stuff (I assume it's twitter bootstrap bumpf). In the end, when you click the play button play gets called on line 111. 31 | 32 | From debugger, play defined on js-snes-player.js:22 . 33 | 34 | Had a look through play function. It fails when it tries to initialize the Sink. sink.js is totally broken. 2 years old, overly complicated and unmaintained. I'll need a new way to play back the audio. 35 | 36 | The business end of the play function is on line 67: 37 | 38 | proxy.on('audioprocess', function(buffer, channelCount){ 39 | 40 | var retval = _spc_play(snes_spc, bufferSize / 2, buf); 41 | _spc_filter_run(filter, buf, bufferSize); 42 | 43 | for (i = 0; i < bufferSize; i ++) { 44 | 45 | // Take a mono stream 46 | if ((i - 1) % 2 == 0) { 47 | buffer[i] = HEAP8[i + buf] / 120; 48 | 49 | } else { 50 | buffer[i] = HEAP8[i + buf - 1] / 120; 51 | 52 | } 53 | } 54 | console.log('Send audio to buffer... Memory points from HEAP ' + i + ' to ' + (i + buf)); 55 | }, 2, null, 12000); 56 | 57 | 58 | This is the audio callback. The buffer "buffer" is the output buffer for the Web Audio API. bufferSize is the number of samples to generate. buf is an offset in to the Emscripten heap. It is where the audio data is calculated and stored by the Emscripten code. 59 | 60 | Plan of attack: disable sink.js and turn the audio generation in to a normal function 61 | 62 | That worked. I took https://developer.mozilla.org/en-US/docs/Web/API/ScriptProcessorNode example code and increased the buffer size. I also had to tweak things slightly as the original code interlieves stereo channels. I had to generate tiwce as much audio data and then extract one channel for playback. 63 | 64 | 65 | Rebuilt with new Emscripten. Sprinkled a bunch of EMSCRIPTEN_KEEPALIVE over the relevant functions in spc.cpp and compiled using emcc -O1. It seems that O2 doesn't work atm. Probably my fault, I'll have a look at this some point. Anyway, O1 seems to be enough to enable asm.js which gives a nice performance boost (10x in my unscientific benchmark) 66 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/snes_spc-0.9.0/.DS_Store -------------------------------------------------------------------------------- /snes_spc-0.9.0/changes.txt: -------------------------------------------------------------------------------- 1 | snes_spc Change Log 2 | ------------------- 3 | 4 | snes_spc 0.9.0 5 | -------------- 6 | - Improved documentation 7 | 8 | - SPC: Added spc_skip() function for quickly seeking in an SPC music 9 | file. Runs 3-4x faster than normal playback using the fast DSP (or about 10 | 43-60X real-time on my 400 MHz Mac). 11 | 12 | - SPC: Added spc_set_tempo() to change tempo of SPC music playback. 13 | 14 | - SPC: Sample generation is now corrected to generate exactly one pair 15 | of samples every 32 clocks without exception. Before it could generate a 16 | few samples more or less depending on how far ahead or behind DSP was at 17 | the moment. 18 | 19 | - SPC: Changed spc_reset() and spc_soft_reset() to also reset output 20 | buffer (see spc.h). 21 | 22 | - SPC: Fixed minor timer counting bug. 23 | 24 | - SPC: Stack pointer wrap-around is now emulated (and without any 25 | noticeable performance hit). 26 | 27 | - SPC: Runs about 5% faster due to various optimizations. 28 | 29 | - SPC: Found way to make fast DSP register accesses cycle-accurate in 30 | most cases, without reducing performance. Allows fast DSP to pass most 31 | of my validation tests. 32 | 33 | - DSP: Added surround disable support to fast DSP again. 34 | 35 | - DSP: Improved voice un-muting to take effect immediately on fast DSP. 36 | 37 | - DSP: Noise shift register now starts at 0x4000 instead of 0x4001 as it 38 | incorrectly did before. 39 | 40 | - Converted library to C++ code internally. A C interface is still 41 | included in spc.h and dsp.h. Note that these are different than the 42 | previous interface, so your code will require minor changes: 43 | 44 | Old SPC code New SPC code 45 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 46 | #include "spc/spc.h" #include "snes_spc/spc.h" 47 | 48 | snes_spc_t* spc; SNES_SPC* spc; 49 | spc = malloc( sizeof (snes_spc_t) ); spc = spc_new(); 50 | spc_init( spc ); 51 | 52 | spc_end_frame( time ); spc_end_frame( spc, time ); 53 | /* etc. */ 54 | 55 | /* done using SPC */ spc_delete( spc ); 56 | 57 | 58 | Old DSP code New DSP code 59 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 60 | #include "spc/spc_dsp.h" #include "snes_spc/dsp.h" 61 | 62 | spc_dsp_init( ram ); SPC_DSP* dsp; 63 | dsp = spc_dsp_new(); 64 | spc_dsp_init( dsp, ram ); 65 | 66 | spc_dsp_run( count ); spc_dsp_run( dsp, count ); 67 | /* etc. */ 68 | 69 | /* done using DSP */ spc_dsp_delete( dsp ); 70 | 71 | 72 | snes_spc 0.8.0 73 | -------------- 74 | - Added several demos 75 | 76 | - Added high-pass/low-pass filter to better match SNES sound 77 | 78 | - Added save state functionality for SPC and accurate DSP (but not fast 79 | DSP) 80 | 81 | - Added emulation of reset switch on NES (soft reset) 82 | 83 | - Made source more compatible with pre-C99 compilers by eliminating 84 | mid-block declarations 85 | 86 | - SPC: Many S-SMP accuracy improvements, mostly in memory access times 87 | 88 | - SPC: S-SMP speed improvements 89 | 90 | - SPC: Added SPC load/save functions and KON checking to help trim 91 | silence from beginning 92 | 93 | - SPC: Changed spc_init() to have you allocate most of the memory used 94 | by the library so you have more control over it 95 | 96 | - DSP: New highly accurate DSP and faster version derived from same code 97 | 98 | - DSP: Changed prefix from dsp_ to spc_dsp_. Your DSP code will require 99 | changes. 100 | 101 | - DSP: Removed surround disable and gain. Gain can now be done with the 102 | dsp_filter module, and surround disable will probably only be 103 | implemented in the fast DSP at some point. 104 | 105 | - DSP: Changed interface to work in clocks rather than samples, 106 | necessary for the new accurate DSP. Sample output is now done with 107 | separate functions. Your DSP code will require changes. 108 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/demo/benchmark.c: -------------------------------------------------------------------------------- 1 | /* Measures performance of SPC emulator. Takes about 4 seconds. 2 | NOTE: This assumes that the program is getting all processor time; you might need to 3 | arrange for this or else the performance will be reported lower than it really is. 4 | 5 | Usage: benchmark [test.spc] 6 | */ 7 | 8 | #include "snes_spc/spc.h" 9 | 10 | #include "demo_util.h" /* error(), load_file() */ 11 | #include 12 | 13 | clock_t start_timing( int seconds ); 14 | 15 | int main( int argc, char** argv ) 16 | { 17 | /* Load SPC */ 18 | long spc_size; 19 | void* spc = load_file( (argc > 1) ? argv [1] : "test.spc", &spc_size ); 20 | SNES_SPC* snes_spc = spc_new(); 21 | if ( !snes_spc ) error( "Out of memory" ); 22 | spc_load_spc( snes_spc, spc, spc_size ); 23 | free( spc ); 24 | 25 | { 26 | /* Repeatedly fill buffer for 4 seconds */ 27 | int const seconds = 4; 28 | #define BUF_SIZE 4096 29 | clock_t end = start_timing( seconds ); 30 | int count = 0; 31 | while ( clock() < end ) 32 | { 33 | static short buf [BUF_SIZE]; 34 | error( spc_play( snes_spc, BUF_SIZE, buf ) ); 35 | count++; 36 | } 37 | 38 | /* Report performance based on how many buffer fills were possible */ 39 | { 40 | double rate = (double) count * BUF_SIZE / (spc_sample_rate * 2 * seconds); 41 | printf( "Performance: %.3fx real-time, or %.0f%% CPU for normal rate\n", 42 | rate, 100.0 / rate ); 43 | } 44 | } 45 | 46 | return 0; 47 | } 48 | 49 | /* Synchronizes with host clock and returns clock() time that is duration seconds from now */ 50 | clock_t start_timing( int duration ) 51 | { 52 | clock_t clock_dur = duration * CLOCKS_PER_SEC; 53 | clock_t time = clock(); 54 | while ( clock() == time ) { } 55 | if ( clock() - time > clock_dur ) 56 | error( "Insufficient clock() time resolution" ); 57 | return clock() + clock_dur; 58 | } 59 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/demo/comm.c: -------------------------------------------------------------------------------- 1 | /* Communicates with SPC the way the SNES would. 2 | 3 | Note: You'll need an "spc_rom.h" file that contains the 64-byte IPL ROM contents */ 4 | 5 | #include "snes_spc/spc.h" 6 | 7 | #include "demo_util.h" 8 | #include 9 | #include 10 | 11 | static SNES_SPC* snes_spc; 12 | 13 | /* Make port access more convenient. Fakes time by simply incrementing it each call. */ 14 | static spc_time_t stime; 15 | static int pread ( int port ) { return spc_read_port( snes_spc, stime++, port ); } 16 | static void pwrite( int port, int data ) { spc_write_port( snes_spc, stime++, port, data ); } 17 | 18 | static unsigned char const spc_rom [spc_rom_size] = { 19 | /* ROM data not provided with emulator */ 20 | #include "spc_rom.h" 21 | }; 22 | 23 | int main() 24 | { 25 | int i; 26 | 27 | /* Data to upload */ 28 | static unsigned char const data [4] = "\xFA\xDE\xD1"; 29 | unsigned const data_addr = 0xF5; /* second I/O port */ 30 | 31 | snes_spc = spc_new(); 32 | if ( !snes_spc ) error( "Out of memory" ); 33 | spc_init_rom( snes_spc, spc_rom ); 34 | spc_reset( snes_spc ); 35 | 36 | /* Simulate reads and writes that SNES code would do */ 37 | 38 | /* Wait for SPC to be ready */ 39 | while ( pread( 0 ) != 0xAA || pread( 1 ) != 0xBB ) { } 40 | 41 | /* Start address */ 42 | pwrite( 2, data_addr & 0xFF ); 43 | pwrite( 3, data_addr >> 8 ); 44 | 45 | /* Tell SPC to start transfer and wait for acknowledgement */ 46 | pwrite( 0, 0xCC ); 47 | pwrite( 1, 0x01 ); 48 | while ( pread( 0 ) != 0xCC ) { } 49 | 50 | /* Send each byte and wait for acknowledgement */ 51 | for ( i = 0; i < 4; i++ ) 52 | { 53 | printf( "%02X ", data [i] ); 54 | pwrite( 1, data [i] ); 55 | pwrite( 0, i ); 56 | while ( pread( 0 ) != i ) { } 57 | } 58 | printf( "\n" ); 59 | 60 | /* Verify that data was transferred properly */ 61 | for ( i = 0; i < 3; i++ ) 62 | printf( "%02X ", pread( i + 1 ) ); 63 | printf( "\n" ); 64 | 65 | printf( "Cycles: %ld\n", (long) stime ); 66 | 67 | spc_delete( snes_spc ); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/demo/demo_util.c: -------------------------------------------------------------------------------- 1 | #include "demo_util.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* Copyright (C) 2007 Shay Green. This module is free software; you 9 | can redistribute it and/or modify it under the terms of the GNU Lesser 10 | General Public License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. This 12 | module is distributed in the hope that it will be useful, but WITHOUT ANY 13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | details. You should have received a copy of the GNU Lesser General Public 16 | License along with this module; if not, write to the Free Software Foundation, 17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18 | 19 | unsigned char* load_file( const char* path, long* size_out ) 20 | { 21 | size_t size; 22 | unsigned char* data; 23 | 24 | FILE* in = fopen( path, "rb" ); 25 | if ( !in ) error( "Couldn't open file" ); 26 | 27 | fseek( in, 0, SEEK_END ); 28 | size = ftell( in ); 29 | if ( size_out ) 30 | *size_out = size; 31 | rewind( in ); 32 | 33 | data = (unsigned char*) malloc( size ); 34 | if ( !data ) error( "Out of memory" ); 35 | 36 | if ( fread( data, 1, size, in ) < size ) error( "Couldn't read file" ); 37 | fclose( in ); 38 | 39 | return data; 40 | } 41 | 42 | void write_file( const char* path, void const* in, long size ) 43 | { 44 | FILE* out = fopen( path, "wb" ); 45 | if ( !out ) error( "Couldn't create file" ); 46 | if ( (long) fwrite( in, 1, size, out ) < size ) error( "Couldn't write file" ); 47 | fclose( out ); 48 | } 49 | 50 | void error( const char* str ) 51 | { 52 | if ( str ) 53 | { 54 | fprintf( stderr, "Error: %s\n", str ); 55 | exit( EXIT_FAILURE ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/demo/demo_util.h: -------------------------------------------------------------------------------- 1 | /* General-purpose utilities used by demos */ 2 | 3 | /* snes_spc 0.9.0 */ 4 | #ifndef DEMO_UTIL_H 5 | #define DEMO_UTIL_H 6 | 7 | /* commonly used headers */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /* If str is not NULL, prints it and exits program, otherwise returns */ 18 | void error( const char* str ); 19 | 20 | /* Loads file and returns pointer to data in memory, allocated with malloc(). 21 | If size_out != NULL, sets *size_out to size of data. */ 22 | unsigned char* load_file( const char* path, long* size_out ); 23 | 24 | /* Writes data to file */ 25 | void write_file( const char* path, void const* in, long size ); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/demo/play_spc.c: -------------------------------------------------------------------------------- 1 | /* Records SPC into wave file. Uses dsp_filter to give more authentic sound. 2 | 3 | Usage: play_spc [test.spc] 4 | */ 5 | 6 | #include "snes_spc/spc.h" 7 | 8 | #include "wave_writer.h" 9 | #include "demo_util.h" /* error(), load_file() */ 10 | 11 | int main( int argc, char** argv ) 12 | { 13 | /* Create emulator and filter */ 14 | SNES_SPC* snes_spc = spc_new(); 15 | SPC_Filter* filter = spc_filter_new(); 16 | if ( !snes_spc || !filter ) error( "Out of memory" ); 17 | 18 | /* Load SPC */ 19 | { 20 | /* Load file into memory */ 21 | long spc_size; 22 | void* spc = load_file( (argc > 1) ? argv [1] : "test.spc", &spc_size ); 23 | 24 | /* Load SPC data into emulator */ 25 | error( spc_load_spc( snes_spc, spc, spc_size ) ); 26 | free( spc ); /* emulator makes copy of data */ 27 | 28 | /* Most SPC files have garbage data in the echo buffer, so clear that */ 29 | spc_clear_echo( snes_spc ); 30 | 31 | /* Clear filter before playing */ 32 | spc_filter_clear( filter ); 33 | } 34 | 35 | /* Record 20 seconds to wave file */ 36 | wave_open( spc_sample_rate, "out.wav" ); 37 | wave_enable_stereo(); 38 | while ( wave_sample_count() < 20 * spc_sample_rate * 2 ) 39 | { 40 | /* Play into buffer */ 41 | #define BUF_SIZE 2048 42 | short buf [BUF_SIZE]; 43 | error( spc_play( snes_spc, BUF_SIZE, buf ) ); 44 | 45 | /* Filter samples */ 46 | spc_filter_run( filter, buf, BUF_SIZE ); 47 | 48 | wave_write( buf, BUF_SIZE ); 49 | } 50 | 51 | /* Cleanup */ 52 | spc_filter_delete( filter ); 53 | spc_delete( snes_spc ); 54 | wave_close(); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/demo/save_state.c: -------------------------------------------------------------------------------- 1 | /* Loads "test.spc", skips 5 seconds, saves exact emulator state to "state.bin", 2 | hen records 5 seconds to "first.wav". When run again, loads this state back into 3 | emulator and records 5 seconds to "second.wav". These two wave files should 4 | be identical. 5 | 6 | Usage: save_state [test.spc] 7 | */ 8 | 9 | #include "snes_spc/spc.h" 10 | 11 | #include "wave_writer.h" 12 | #include "demo_util.h" /* error(), load_file() */ 13 | 14 | static SNES_SPC* snes_spc; 15 | 16 | void record_wav( const char* path, int secs ) 17 | { 18 | /* Start writing wave file */ 19 | wave_open( spc_sample_rate, path ); 20 | wave_enable_stereo(); 21 | while ( wave_sample_count() < secs * spc_sample_rate * 2 ) 22 | { 23 | /* Play into buffer */ 24 | #define BUF_SIZE 2048 25 | short buf [BUF_SIZE]; 26 | error( spc_play( snes_spc, BUF_SIZE, buf ) ); 27 | 28 | wave_write( buf, BUF_SIZE ); 29 | } 30 | wave_close(); 31 | } 32 | 33 | void state_save( unsigned char** out, void* in, size_t size ) 34 | { 35 | memcpy( *out, in, size ); 36 | *out += size; 37 | } 38 | 39 | void make_save_state( const char* path ) 40 | { 41 | /* Load SPC */ 42 | long spc_size; 43 | void* spc = load_file( path, &spc_size ); 44 | error( spc_load_spc( snes_spc, spc, spc_size ) ); 45 | free( spc ); 46 | spc_clear_echo( snes_spc ); 47 | 48 | /* Skip several seconds */ 49 | error( spc_play( snes_spc, 5 * spc_sample_rate * 2, 0 ) ); 50 | 51 | /* Save state to file */ 52 | { 53 | static unsigned char state [spc_state_size]; /* buffer large enough for data */ 54 | unsigned char* out = state; 55 | spc_copy_state( snes_spc, &out, state_save ); 56 | write_file( "state.bin", state, out - state ); 57 | } 58 | 59 | record_wav( "first.wav", 5 ); 60 | } 61 | 62 | void state_load( unsigned char** in, void* out, size_t size ) 63 | { 64 | memcpy( out, *in, size ); 65 | *in += size; 66 | } 67 | 68 | void use_save_state() 69 | { 70 | /* Load state into memory */ 71 | long state_size; 72 | unsigned char* state = load_file( "state.bin", &state_size ); 73 | 74 | /* Load into emulator */ 75 | unsigned char* in = state; 76 | spc_copy_state( snes_spc, &in, state_load ); 77 | assert( in - state <= state_size ); /* be sure it didn't read past end */ 78 | 79 | record_wav( "second.wav", 5 ); 80 | } 81 | 82 | int file_exists( const char* path ) 83 | { 84 | FILE* file = fopen( path, "rb" ); 85 | if ( !file ) 86 | return 0; 87 | 88 | fclose( file ); 89 | return 1; 90 | } 91 | 92 | int main( int argc, char** argv ) 93 | { 94 | snes_spc = spc_new(); 95 | if ( !snes_spc ) error( "Out of memory" ); 96 | 97 | /* Make new state if it doesn't exist, otherwise load it and 98 | record to wave file */ 99 | if ( !file_exists( "state.bin" ) ) 100 | make_save_state( (argc > 1) ? argv [1] : "test.spc" ); 101 | else 102 | use_save_state(); 103 | 104 | spc_delete( snes_spc ); 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/demo/trim_spc.c: -------------------------------------------------------------------------------- 1 | /* Trims silence off beginning of SPC file. 2 | Requires the accurate DSP; won't compile with the fast DSP. 3 | Please note that the algorithm could be improved; this is just 4 | a simple example showing the idea. 5 | 6 | Usage: trim_spc [test.spc [trimmed.spc]] 7 | */ 8 | 9 | #include "snes_spc/spc.h" 10 | 11 | #include "demo_util.h" /* error(), load_file() */ 12 | 13 | /* Change to 1 to have it trim to next key on event rather than trim silence */ 14 | enum { use_kon_check = 0 }; 15 | 16 | /* True if all count samples from in are silent (or very close to it) */ 17 | int is_silent( short const* in, int count ); 18 | 19 | int main( int argc, char** argv ) 20 | { 21 | /* Load file into memory */ 22 | long spc_size; 23 | void* spc = load_file( (argc > 1) ? argv [1] : "test.spc", &spc_size ); 24 | 25 | /* Load into emulator */ 26 | SNES_SPC* snes_spc = spc_new(); 27 | if ( !snes_spc ) error( "Out of memory" ); 28 | error( spc_load_spc( snes_spc, spc, spc_size ) ); 29 | 30 | /* Expand SPC data so there's enough room for emulator to save to. 31 | We simply overwrite the emulator data in the old SPC file rather 32 | than creating new SPC data. This preserves the text tags from 33 | the old file. */ 34 | if ( spc_size < spc_file_size ) 35 | { 36 | spc_size = spc_file_size; 37 | spc = realloc( spc, spc_size ); /* leaks memory if allocation fails */ 38 | if ( !spc ) error( "Out of memory" ); 39 | } 40 | 41 | /* Keep saving SPC, then playing a little more. Once SPC becomes non-silent, 42 | write the SPC data saved just before this. */ 43 | { 44 | long samples_trimmed = 0; 45 | while ( 1 ) 46 | { 47 | #define BUF_SIZE 1024 48 | short buf [BUF_SIZE]; 49 | 50 | if ( samples_trimmed > 10 * spc_sample_rate * 2 ) 51 | error( "Excess silence found" ); 52 | 53 | spc_clear_echo( snes_spc ); 54 | spc_save_spc( snes_spc, spc ); 55 | 56 | /* Fill buffer */ 57 | error( spc_play( snes_spc, BUF_SIZE, buf ) ); 58 | samples_trimmed += BUF_SIZE; 59 | 60 | /* See if SPC became non-silent */ 61 | if ( use_kon_check ? spc_check_kon( snes_spc ) : !is_silent( buf, BUF_SIZE ) ) 62 | break; 63 | } 64 | 65 | printf( "Trimmed %.1f seconds\n", (double) samples_trimmed / spc_sample_rate / 2 ); 66 | } 67 | 68 | spc_delete( snes_spc ); 69 | write_file( (argc > 2) ? argv [2] : "trimmed.spc", spc, spc_size ); 70 | 71 | return 0; 72 | } 73 | 74 | int is_silent( short const* in, int count ) 75 | { 76 | unsigned const threshold = 0x10; 77 | while ( count-- ) 78 | { 79 | if ( (unsigned) (*in++ + threshold / 2) > threshold ) 80 | return 0; 81 | } 82 | return 1; 83 | } 84 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/demo/wave_writer.c: -------------------------------------------------------------------------------- 1 | /* snes_spc 0.9.0. http://www.slack.net/~ant/ */ 2 | 3 | #include "wave_writer.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | /* Copyright (C) 2003-2007 Shay Green. This module is free software; you 10 | can redistribute it and/or modify it under the terms of the GNU Lesser 11 | General Public License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. This 13 | module is distributed in the hope that it will be useful, but WITHOUT ANY 14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 16 | details. You should have received a copy of the GNU Lesser General Public 17 | License along with this module; if not, write to the Free Software Foundation, 18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 19 | 20 | enum { buf_size = 32768 * 2 }; 21 | enum { header_size = 0x2C }; 22 | 23 | typedef short sample_t; 24 | 25 | static unsigned char* buf; 26 | static FILE* file; 27 | static long sample_count_; 28 | static long sample_rate_; 29 | static long buf_pos; 30 | static int chan_count; 31 | 32 | static void exit_with_error( const char* str ) 33 | { 34 | printf( "Error: %s\n", str ); getchar(); 35 | exit( EXIT_FAILURE ); 36 | } 37 | 38 | void wave_open( long sample_rate, const char* filename ) 39 | { 40 | sample_count_ = 0; 41 | sample_rate_ = sample_rate; 42 | buf_pos = header_size; 43 | chan_count = 1; 44 | 45 | buf = (unsigned char*) malloc( buf_size * sizeof *buf ); 46 | if ( !buf ) 47 | exit_with_error( "Out of memory" ); 48 | 49 | file = fopen( filename, "wb" ); 50 | if ( !file ) 51 | exit_with_error( "Couldn't open WAVE file for writing" ); 52 | 53 | setvbuf( file, 0, _IOFBF, 32 * 1024L ); 54 | } 55 | 56 | void wave_enable_stereo( void ) 57 | { 58 | chan_count = 2; 59 | } 60 | 61 | static void flush_() 62 | { 63 | if ( buf_pos && !fwrite( buf, buf_pos, 1, file ) ) 64 | exit_with_error( "Couldn't write WAVE data" ); 65 | buf_pos = 0; 66 | } 67 | 68 | void wave_write( short const* in, long remain ) 69 | { 70 | sample_count_ += remain; 71 | while ( remain ) 72 | { 73 | if ( buf_pos >= buf_size ) 74 | flush_(); 75 | 76 | { 77 | unsigned char* p = &buf [buf_pos]; 78 | long n = (buf_size - buf_pos) / sizeof (sample_t); 79 | if ( n > remain ) 80 | n = remain; 81 | remain -= n; 82 | 83 | /* convert to LSB first format */ 84 | while ( n-- ) 85 | { 86 | int s = *in++; 87 | *p++ = (unsigned char) s; 88 | *p++ = (unsigned char) (s >> 8); 89 | } 90 | 91 | buf_pos = p - buf; 92 | assert( buf_pos <= buf_size ); 93 | } 94 | } 95 | } 96 | 97 | long wave_sample_count( void ) 98 | { 99 | return sample_count_; 100 | } 101 | 102 | static void set_le32( void* p, unsigned long n ) 103 | { 104 | ((unsigned char*) p) [0] = (unsigned char) n; 105 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); 106 | ((unsigned char*) p) [2] = (unsigned char) (n >> 16); 107 | ((unsigned char*) p) [3] = (unsigned char) (n >> 24); 108 | } 109 | 110 | void wave_close( void ) 111 | { 112 | if ( file ) 113 | { 114 | /* generate header */ 115 | unsigned char h [header_size] = 116 | { 117 | 'R','I','F','F', 118 | 0,0,0,0, /* length of rest of file */ 119 | 'W','A','V','E', 120 | 'f','m','t',' ', 121 | 0x10,0,0,0, /* size of fmt chunk */ 122 | 1,0, /* uncompressed format */ 123 | 0,0, /* channel count */ 124 | 0,0,0,0, /* sample rate */ 125 | 0,0,0,0, /* bytes per second */ 126 | 0,0, /* bytes per sample frame */ 127 | 16,0, /* bits per sample */ 128 | 'd','a','t','a', 129 | 0,0,0,0, /* size of sample data */ 130 | /* ... */ /* sample data */ 131 | }; 132 | long ds = sample_count_ * sizeof (sample_t); 133 | int frame_size = chan_count * sizeof (sample_t); 134 | 135 | set_le32( h + 0x04, header_size - 8 + ds ); 136 | h [0x16] = chan_count; 137 | set_le32( h + 0x18, sample_rate_ ); 138 | set_le32( h + 0x1C, sample_rate_ * frame_size ); 139 | h [0x20] = frame_size; 140 | set_le32( h + 0x28, ds ); 141 | 142 | flush_(); 143 | 144 | /* write header */ 145 | fseek( file, 0, SEEK_SET ); 146 | fwrite( h, sizeof h, 1, file ); 147 | 148 | fclose( file ); 149 | file = 0; 150 | free( buf ); 151 | buf = 0; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/demo/wave_writer.h: -------------------------------------------------------------------------------- 1 | /* WAVE sound file writer for recording 16-bit output during program development */ 2 | 3 | #ifndef WAVE_WRITER_H 4 | #define WAVE_WRITER_H 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | void wave_open( long sample_rate, const char* filename ); 11 | void wave_enable_stereo( void ); 12 | void wave_write( short const* in, long count ); 13 | long wave_sample_count( void ); 14 | void wave_close( void ); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/fast_dsp/SPC_DSP.h: -------------------------------------------------------------------------------- 1 | // Fast SNES SPC-700 DSP emulator (about 3x speed of accurate one) 2 | 3 | // snes_spc 0.9.0 4 | #ifndef SPC_DSP_H 5 | #define SPC_DSP_H 6 | 7 | #include "blargg_common.h" 8 | 9 | class SPC_DSP { 10 | public: 11 | typedef BOOST::uint8_t uint8_t; 12 | 13 | // Setup 14 | 15 | // Initializes DSP and has it use the 64K RAM provided 16 | void init( void* ram_64k ); 17 | 18 | // Sets destination for output samples. If out is NULL or out_size is 0, 19 | // doesn't generate any. 20 | typedef short sample_t; 21 | void set_output( sample_t* out, int out_size ); 22 | 23 | // Number of samples written to output since it was last set, always 24 | // a multiple of 2. Undefined if more samples were generated than 25 | // output buffer could hold. 26 | int sample_count() const; 27 | 28 | // Emulation 29 | 30 | // Resets DSP to power-on state 31 | void reset(); 32 | 33 | // Emulates pressing reset switch on SNES 34 | void soft_reset(); 35 | 36 | // Reads/writes DSP registers. For accuracy, you must first call spc_run_dsp() 37 | // to catch the DSP up to present. 38 | int read ( int addr ) const; 39 | void write( int addr, int data ); 40 | 41 | // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks 42 | // a pair of samples is be generated. 43 | void run( int clock_count ); 44 | 45 | // Sound control 46 | 47 | // Mutes voices corresponding to non-zero bits in mask (overrides VxVOL with 0). 48 | // Reduces emulation accuracy. 49 | enum { voice_count = 8 }; 50 | void mute_voices( int mask ); 51 | 52 | // If true, prevents channels and global volumes from being phase-negated 53 | void disable_surround( bool disable = true ); 54 | 55 | // State 56 | 57 | // Resets DSP and uses supplied values to initialize registers 58 | enum { register_count = 128 }; 59 | void load( uint8_t const regs [register_count] ); 60 | 61 | // DSP register addresses 62 | 63 | // Global registers 64 | enum { 65 | r_mvoll = 0x0C, r_mvolr = 0x1C, 66 | r_evoll = 0x2C, r_evolr = 0x3C, 67 | r_kon = 0x4C, r_koff = 0x5C, 68 | r_flg = 0x6C, r_endx = 0x7C, 69 | r_efb = 0x0D, r_pmon = 0x2D, 70 | r_non = 0x3D, r_eon = 0x4D, 71 | r_dir = 0x5D, r_esa = 0x6D, 72 | r_edl = 0x7D, 73 | r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F 74 | }; 75 | 76 | // Voice registers 77 | enum { 78 | v_voll = 0x00, v_volr = 0x01, 79 | v_pitchl = 0x02, v_pitchh = 0x03, 80 | v_srcn = 0x04, v_adsr0 = 0x05, 81 | v_adsr1 = 0x06, v_gain = 0x07, 82 | v_envx = 0x08, v_outx = 0x09 83 | }; 84 | 85 | public: 86 | enum { extra_size = 16 }; 87 | sample_t* extra() { return m.extra; } 88 | sample_t const* out_pos() const { return m.out; } 89 | public: 90 | BLARGG_DISABLE_NOTHROW 91 | 92 | typedef BOOST::int8_t int8_t; 93 | typedef BOOST::int16_t int16_t; 94 | 95 | enum { echo_hist_size = 8 }; 96 | 97 | enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; 98 | enum { brr_buf_size = 12 }; 99 | struct voice_t 100 | { 101 | int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) 102 | int* buf_pos; // place in buffer where next samples will be decoded 103 | int interp_pos; // relative fractional position in sample (0x1000 = 1.0) 104 | int brr_addr; // address of current BRR block 105 | int brr_offset; // current decoding offset in BRR block 106 | int kon_delay; // KON delay/current setup phase 107 | env_mode_t env_mode; 108 | int env; // current envelope level 109 | int hidden_env; // used by GAIN mode 7, very obscure quirk 110 | int volume [2]; // copy of volume from DSP registers, with surround disabled 111 | int enabled; // -1 if enabled, 0 if muted 112 | }; 113 | private: 114 | struct state_t 115 | { 116 | uint8_t regs [register_count]; 117 | 118 | // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) 119 | int echo_hist [echo_hist_size * 2] [2]; 120 | int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] 121 | 122 | int every_other_sample; // toggles every sample 123 | int kon; // KON value when last checked 124 | int noise; 125 | int echo_offset; // offset from ESA in echo buffer 126 | int echo_length; // number of bytes that echo_offset will stop at 127 | int phase; // next clock cycle to run (0-31) 128 | unsigned counters [4]; 129 | 130 | int new_kon; 131 | int t_koff; 132 | 133 | voice_t voices [voice_count]; 134 | 135 | unsigned* counter_select [32]; 136 | 137 | // non-emulation state 138 | uint8_t* ram; // 64K shared RAM between DSP and SMP 139 | int mute_mask; 140 | int surround_threshold; 141 | sample_t* out; 142 | sample_t* out_end; 143 | sample_t* out_begin; 144 | sample_t extra [extra_size]; 145 | }; 146 | state_t m; 147 | 148 | void init_counter(); 149 | void run_counter( int ); 150 | void soft_reset_common(); 151 | void write_outline( int addr, int data ); 152 | void update_voice_vol( int addr ); 153 | }; 154 | 155 | #include 156 | 157 | inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } 158 | 159 | inline int SPC_DSP::read( int addr ) const 160 | { 161 | assert( (unsigned) addr < register_count ); 162 | return m.regs [addr]; 163 | } 164 | 165 | inline void SPC_DSP::update_voice_vol( int addr ) 166 | { 167 | int l = (int8_t) m.regs [addr + v_voll]; 168 | int r = (int8_t) m.regs [addr + v_volr]; 169 | 170 | if ( l * r < m.surround_threshold ) 171 | { 172 | // signs differ, so negate those that are negative 173 | l ^= l >> 7; 174 | r ^= r >> 7; 175 | } 176 | 177 | voice_t& v = m.voices [addr >> 4]; 178 | int enabled = v.enabled; 179 | v.volume [0] = l & enabled; 180 | v.volume [1] = r & enabled; 181 | } 182 | 183 | inline void SPC_DSP::write( int addr, int data ) 184 | { 185 | assert( (unsigned) addr < register_count ); 186 | 187 | m.regs [addr] = (uint8_t) data; 188 | int low = addr & 0x0F; 189 | if ( low < 0x2 ) // voice volumes 190 | { 191 | update_voice_vol( low ^ addr ); 192 | } 193 | else if ( low == 0xC ) 194 | { 195 | if ( addr == r_kon ) 196 | m.new_kon = (uint8_t) data; 197 | 198 | if ( addr == r_endx ) // always cleared, regardless of data written 199 | m.regs [r_endx] = 0; 200 | } 201 | } 202 | 203 | inline void SPC_DSP::disable_surround( bool disable ) 204 | { 205 | m.surround_threshold = disable ? 0 : -0x4000; 206 | } 207 | 208 | #define SPC_NO_COPY_STATE_FUNCS 1 209 | 210 | #define SPC_LESS_ACCURATE 1 211 | 212 | #endif 213 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/readme.txt: -------------------------------------------------------------------------------- 1 | snes_spc 0.9.0: SNES SPC-700 APU Emulator 2 | ----------------------------------------- 3 | This library includes a full SPC emulator and an S-DSP emulator that can 4 | be used on its own. Two S-DSP emulators are available: a highly accurate 5 | one for use in a SNES emulator, and a 3x faster one for use in an SPC 6 | music player or a resource-limited SNES emulator. 7 | 8 | * Can be used from C and C++ code 9 | * Full SPC-700 APU emulator with cycle accuracy in most cases 10 | * Loads, plays, and saves SPC music files 11 | * Can save and load exact full emulator state 12 | * DSP voice muting, surround sound disable, and song tempo adjustment 13 | * Uses 7% CPU average on 400 MHz Mac to play an SPC using fast DSP 14 | 15 | The accurate DSP emulator is based on past research by others and 16 | hundreds of hours of recent research by me. It passes over a hundred 17 | strenuous timing and behavior validation tests that were also run on the 18 | SNES. As far as I know, it's the first DSP emulator with cycle accuracy, 19 | properly emulating every DSP register and memory access at the exact SPC 20 | cycle it occurs at, whereas previous DSP emulators emulated these only 21 | to the nearest sample (which occurs every 32 clocks). 22 | 23 | Author : Shay Green 24 | Website: http://www.slack.net/~ant/ 25 | Forum : http://groups.google.com/group/blargg-sound-libs 26 | License: GNU Lesser General Public License (LGPL) 27 | 28 | 29 | Getting Started 30 | --------------- 31 | Build a program consisting of demo/play_spc.c, demo/demo_util.c, 32 | demo/wave_writer.c, and all source files in snes_spc/. Put an SPC music 33 | file in the same directory and name it "test.spc". Running the program 34 | should generate the recording "out.wav". 35 | 36 | Read snes_spc.txt for more information. Post to the discussion forum for 37 | assistance. 38 | 39 | 40 | Files 41 | ----- 42 | snes_spc.txt Documentation 43 | changes.txt Change log 44 | license.txt GNU LGPL license 45 | 46 | demo/ 47 | play_spc.c Records SPC file to wave sound file 48 | benchmark.c Finds how fast emulator runs on your computer 49 | trim_spc.c Trims silence off beginning of an SPC file 50 | save_state.c Saves/loads exact emulator state to/from file 51 | comm.c Communicates with SPC how SNES would 52 | demo_util.h General utility functions used by demos 53 | demo_util.c 54 | wave_writer.h WAVE sound file writer used for demo output 55 | wave_writer.c 56 | 57 | fast_dsp/ Optional standalone fast DSP emulator 58 | SPC_DSP.h To use with full SPC emulator, move into 59 | SPC_DSP.cpp snes_spc/ and replace original files 60 | 61 | snes_spc/ Library sources 62 | blargg_config.h Configuration (modify as necessary) 63 | 64 | spc.h C interface to SPC emulator and sound filter 65 | spc.cpp 66 | 67 | SPC_Filter.h Optional filter to make sound more authentic 68 | SPC_Filter.cpp 69 | 70 | SNES_SPC.h Full SPC emulator 71 | SNES_SPC.cpp 72 | SNES_SPC_misc.cpp 73 | SNES_SPC_state.cpp 74 | SPC_CPU.h 75 | 76 | dsp.h C interface to DSP emulator 77 | dsp.cpp 78 | 79 | SPC_DSP.h Standalone accurate DSP emulator 80 | SPC_DSP.cpp 81 | blargg_common.h 82 | blargg_endian.h 83 | blargg_source.h 84 | 85 | -- 86 | Shay Green 87 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc.txt: -------------------------------------------------------------------------------- 1 | snes_spc 0.9.0: SNES SPC-700 APU Emulator 2 | ----------------------------------------- 3 | Author : Shay Green 4 | Website: http://www.slack.net/~ant/ 5 | Forum : http://groups.google.com/group/blargg-sound-libs 6 | License: GNU Lesser General Public License (LGPL) 7 | 8 | 9 | Contents 10 | -------- 11 | * C and C++ Interfaces 12 | * Overview 13 | * Full SPC Emulation 14 | * DSP Emulation 15 | * SPC Music Playback 16 | * State Copying 17 | * Library Compilation 18 | * Error handling 19 | * Solving Problems 20 | * Accurate S-DSP Limitations 21 | * Fast S-DSP Limitations 22 | * S-SMP Limitations 23 | * To Do 24 | * Thanks 25 | 26 | 27 | C and C++ Interfaces 28 | -------------------- 29 | The library includes a C interface in spc.h and dsp.h, which can be used 30 | from C and C++. This C interface is referred to in the following 31 | documentation. If you're building this as a shared library (rather than 32 | linking statically), you should use the C interface since it will change 33 | less in future versions. 34 | 35 | The native C++ interface is in the header files SNES_SPC.h, SPC_DSP.h, 36 | and SPC_Filter.h, and the two interfaces can be freely mixed in C++ 37 | code. Conversion between the two interfaces generally follows a pattern: 38 | 39 | C interface C++ interface 40 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 41 | SNES_SPC* spc; SNES_SPC* spc; 42 | 43 | spc = spc_new(); spc = new SNES_SPC; 44 | 45 | spc_play( spc, count, buf ); spc->play( count, buf ); 46 | 47 | spc_sample_rate SNES_SPC::sample_rate 48 | 49 | spc_delete( spc ); delete spc; 50 | 51 | 52 | Overview 53 | -------- 54 | There are three main roles for this library: 55 | * Full SPC emulation in a SNES emulator 56 | * DSP emulation in a SNES emulator (where you emulate the SMP CPU) 57 | * SPC playback in an SPC music file player 58 | 59 | Each of these uses are described separately below. 60 | 61 | 62 | Full SPC Emulation 63 | ------------------ 64 | See spc.h for full function reference (SNES_SPC.h if using C++). 65 | 66 | * Create SPC emulator with spc_new() and check for NULL. 67 | 68 | * Call spc_init_rom() with a pointer to the 64-byte IPL ROM dump (not 69 | included with library). 70 | 71 | * When your emulated SNES is powered on, call spc_reset(). When the 72 | reset switch is pressed, call spc_soft_reset(). 73 | 74 | * Call spc_set_output() with your output buffer, then do emulation. 75 | 76 | * When the SNES CPU accesses APU ports, call spc_read_port() and 77 | spc_write_port(). 78 | 79 | * When your emulator's timebase is going back to 0, call 80 | spc_end_frame(), usually at the end of a video frame or scanline. 81 | 82 | * Periodically play samples from your buffer. Use spc_sample_count() to 83 | find out how many samples have been written, then spc_set_output() after 84 | you've made more space in your buffer. 85 | 86 | * Save/load full emulator state with spc_copy_state(). 87 | 88 | * You can save as an SPC music file with spc_save_spc(). 89 | 90 | * When done, use spc_delete() to free memory. 91 | 92 | 93 | DSP Emulation 94 | ------------- 95 | See dsp.h for full function reference (SPC_DSP.h if using C++). 96 | 97 | * Create DSP emulator with spc_dsp_new() and check for NULL. 98 | 99 | * Let the DSP know where your 64K RAM is with spc_dsp_init(). 100 | 101 | * When your emulated SNES is powered on, call spc_dsp_reset(). When the 102 | reset switch is pressed, call spc_dsp_soft_reset(). 103 | 104 | * Call spc_dsp_set_output() with your output buffer, then do emulation. 105 | 106 | * Use spc_dsp_run() to run DSP for specified number of clocks (1024000 107 | per second). Every 32 clocks a pair of samples is added to your output 108 | buffer. 109 | 110 | * Use spc_dsp_read() and spc_dsp_write() to handle DSP reads/writes from 111 | the S-SMP. Before calling these always catch the DSP up to present time 112 | with spc_dsp_run(). 113 | 114 | * Periodically play samples from your buffer. Use spc_dsp_sample_count() 115 | to find out how many samples have been written, then 116 | spc_dsp_set_output() after you've made more space in your buffer. 117 | 118 | * Use spc_dsp_copy_state() to save/load full DSP state. 119 | 120 | * When done, use spc_delete() to free memory. 121 | 122 | 123 | SPC Music Playback 124 | ------------------ 125 | See spc.h for full function reference (SNES_SPC.h if using C++). 126 | 127 | * Create SPC emulator with spc_new() and check for NULL. 128 | 129 | * Load SPC with spc_load_spc() and check for error. 130 | 131 | * Optionally cear echo buffer with spc_clear_echo(). Many SPCs have 132 | garbage in echo buffer, which causes noise at the beginning. 133 | 134 | * Generate samples as needed with spc_play(). 135 | 136 | * When done, use spc_delete() to free memory. 137 | 138 | * For a more complete game music playback library, use Game_Music_Emu 139 | 140 | 141 | State Copying 142 | ------------- 143 | The SPC and DSP modules include state save/load functions. They take a 144 | pointer to a pointer to a buffer to store state, and a copy function. 145 | This copy function can either copy data to the buffer or from it, 146 | allowing state save and restore with the same library function. The 147 | internal save state format allows for future expansion without making 148 | previous save states unusable. 149 | 150 | The SPC save state format puts the most important parts first to make it 151 | easier to manually examine. It's organized as follows: 152 | 153 | Offset Size Data 154 | - - - - - - - - - - - - - - - - - - 155 | 0 $10000 SPC RAM 156 | $10000 $10 SMP $F0-$FF registers 157 | $10010 4 SMP $F4-$F8 output registers 158 | $10014 2 PC 159 | $10016 1 A 160 | $10017 1 X 161 | $10018 1 Y 162 | $10019 1 PSW 163 | $1001A 1 SP 164 | $1001B 5 internal 165 | $10020 $80 DSP registers 166 | $100A0 ... internal 167 | 168 | 169 | Library Compilation 170 | ------------------- 171 | While this library is in C++, it has been written to easily link in a C 172 | program *without* needing the standard C++ library. It doesn't use 173 | exception handling or run-time type information (RTTI), so you can 174 | disable these in your C++ compiler to increase efficiency. 175 | 176 | If you're building a shared library (DLL), I recommend only exporting 177 | the C interfaces in spc.h and dsp.h, as the C++ interfaces expose 178 | implementation details that will break link compatibility across 179 | versions. 180 | 181 | If you're using C and compiling with GCC, I recommend the following 182 | command-line options when compiling the library source, otherwise GCC 183 | will insert calls to the standard C++ library and require that it be 184 | linked in: 185 | 186 | -fno-rtti -fno-exceptions 187 | 188 | For maximum optimization, see the NDEBUG and BLARGG_NONPORTABLE options 189 | in blargg_config. If using GCC, you can enable these by adding the 190 | following command-line options when you invoke gcc. If you encounter 191 | problems, try without -DBLARGG_NONPORTABLE; if that works, contact me so 192 | I can figure out why BLARGG_NONPORTABLE was causing it to fail. 193 | 194 | -O3 -DNDEBUG -DBLARGG_NONPORTABLE -fno-rtti -fno-exceptions 195 | 196 | 197 | 198 | Error handling 199 | -------------- 200 | Functions which can fail have a return type of spc_err_t (blargg_err_t 201 | in the C++ interfaces), which is a pointer to an error string (const 202 | char*). If a function is successful it returns NULL. Errors that you can 203 | easily avoid are checked with debug assertions; spc_err_t return values 204 | are only used for genuine run-time errors that can't be easily predicted 205 | in advance (out of memory, I/O errors, incompatible file data). Your 206 | code should check all error values. 207 | 208 | To improve usability for C programmers, C++ programmers unfamiliar with 209 | exceptions, and compatibility with older C++ compilers, the library does 210 | *not* throw any C++ exceptions and uses malloc() instead of the standard 211 | operator new. This means that you *must* check for NULL when creating a 212 | library object with the new operator. 213 | 214 | 215 | Solving Problems 216 | ---------------- 217 | If you're having problems, try the following: 218 | 219 | * If you're getting garbled sound, try this simple siren generator in 220 | place of your call to play(). This will quickly tell whether the problem 221 | is in the library or in your code. 222 | 223 | static void play_siren( long count, short* out ) 224 | { 225 | static double a, a2; 226 | while ( count-- ) 227 | *out++ = 0x2000 * sin( a += .1 + .05*sin( a2+=.00005 ) ); 228 | } 229 | 230 | * Enable debugging support in your environment. This enables assertions 231 | and other run-time checks. 232 | 233 | * Turn the compiler's optimizer is off. Sometimes an optimizer generates 234 | bad code. 235 | 236 | * If multiple threads are being used, ensure that only one at a time is 237 | accessing a given set of objects from the library. This library is not 238 | in general thread-safe, though independent objects can be used in 239 | separate threads. 240 | 241 | * If all else fails, see if the demos work. 242 | 243 | 244 | Accurate S-DSP Limitations 245 | -------------------------- 246 | * Power-up and soft reset behavior might have slight inaccuracies. 247 | 248 | * Muting (FLG bit 6) behavior when toggling bit very rapidly is not 249 | emulated properly. 250 | 251 | * No other known inaccuracies. Has passed 100+ strenuous tests. 252 | 253 | 254 | Fast S-DSP Limitations 255 | ---------------------- 256 | * Uses faster sample calculations except in cases where exact value is 257 | actually important (BRR decoding, and gaussian interpolation combined 258 | with pitch modulation). 259 | 260 | * Stops decoding BRR data when a voice's envelope has released to 261 | silence. 262 | 263 | * Emulates 32 clocks at a time, so DSP register and memory accesses are 264 | all done in a bunch rather than spread out. Even though, some clever 265 | code makes register accesses separated by 40 or so clocks occur with 266 | cycle-accurate timing. 267 | 268 | 269 | S-SMP Limitations 270 | ----------------- 271 | * Opcode fetches and indirect pointers are always read directly from 272 | memory, even for the $F0-$FF region, and the DSP is not caught up for 273 | these fetches. 274 | 275 | * Attempts to perversely execute data in registers or an area being 276 | modified by echo will not be emulated properly. 277 | 278 | * Has not been thoroughly tested. 279 | 280 | * Test register ($F0) is not implemented. 281 | 282 | * Echo buffer can overwrite IPL ROM area, and does not correctly update 283 | extra RAM there. 284 | 285 | 286 | To Do 287 | ----- 288 | * I'd like feedback on the interface and any ways to improve it. In 289 | particular, the differing features between the accurate and fast DSP 290 | emulators might make it harder to cleanly switch between them without 291 | modifying source code. 292 | 293 | * Finish thorough tests on SMP memory access times. 294 | 295 | * Finish thorough tests on SMP instruction behavior (flags, registers). 296 | 297 | * Finish thorough tests on SMP timers. 298 | 299 | * Finish power-up and reset behavior testing. 300 | 301 | * Come up with best starting conditions to play an SPC and implement in 302 | hardware SNES SPC player for verification. 303 | 304 | 305 | Thanks 306 | ------ 307 | Thanks to Anti-Resonance's SPC2ROM and help getting SPCs playing on my 308 | SNES in the first place, then Brad Martin's openspc and Chris Moeller's 309 | openspc++ C++ adaptation, giving me a good SPC emulator to start with 310 | several years ago. Thanks to Richard Bannister, Mahendra Tallur, Shazz, 311 | nenolod, theHobbit, Johan Samuelsson, nes6502, and Micket for helping 312 | test my Game_Music_Emu library. Thanks to hcs for help in converting to 313 | C for the Rockbox port. Thanks to byuu (bsnes author) and pagefault and 314 | Nach (zsnes team) for testing and using my new rewritten DSP in their 315 | emulators. Thanks to anomie for his good SNES documentation and 316 | discussions with me to keep it up to date with my latest findings. 317 | -- 318 | Shay Green 319 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/snes_spc-0.9.0/snes_spc/.DS_Store -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/SNES_SPC.cpp: -------------------------------------------------------------------------------- 1 | // Core SPC emulation: CPU, timers, SMP registers, memory 2 | 3 | // snes_spc 0.9.0. http://www.slack.net/~ant/ 4 | 5 | #include "SNES_SPC.h" 6 | 7 | #include 8 | 9 | /* Copyright (C) 2004-2007 Shay Green. This module is free software; you 10 | can redistribute it and/or modify it under the terms of the GNU Lesser 11 | General Public License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. This 13 | module is distributed in the hope that it will be useful, but WITHOUT ANY 14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 16 | details. You should have received a copy of the GNU Lesser General Public 17 | License along with this module; if not, write to the Free Software Foundation, 18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 19 | 20 | #include "blargg_source.h" 21 | 22 | #define RAM (m.ram.ram) 23 | #define REGS (m.smp_regs [0]) 24 | #define REGS_IN (m.smp_regs [1]) 25 | 26 | // (n ? n : 256) 27 | #define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) 28 | 29 | // Note: SPC_MORE_ACCURACY exists mainly so I can run my validation tests, which 30 | // do crazy echo buffer accesses. 31 | #ifndef SPC_MORE_ACCURACY 32 | #define SPC_MORE_ACCURACY 0 33 | #endif 34 | 35 | #ifdef BLARGG_ENABLE_OPTIMIZER 36 | #include BLARGG_ENABLE_OPTIMIZER 37 | #endif 38 | 39 | 40 | //// Timers 41 | 42 | #if SPC_DISABLE_TEMPO 43 | #define TIMER_DIV( t, n ) ((n) >> t->prescaler) 44 | #define TIMER_MUL( t, n ) ((n) << t->prescaler) 45 | #else 46 | #define TIMER_DIV( t, n ) ((n) / t->prescaler) 47 | #define TIMER_MUL( t, n ) ((n) * t->prescaler) 48 | #endif 49 | 50 | SNES_SPC::Timer* SNES_SPC::run_timer_( Timer* t, rel_time_t time ) 51 | { 52 | int elapsed = TIMER_DIV( t, time - t->next_time ) + 1; 53 | t->next_time += TIMER_MUL( t, elapsed ); 54 | 55 | if ( t->enabled ) 56 | { 57 | int remain = IF_0_THEN_256( t->period - t->divider ); 58 | int divider = t->divider + elapsed; 59 | int over = elapsed - remain; 60 | if ( over >= 0 ) 61 | { 62 | int n = over / t->period; 63 | t->counter = (t->counter + 1 + n) & 0x0F; 64 | divider = over - n * t->period; 65 | } 66 | t->divider = (uint8_t) divider; 67 | } 68 | return t; 69 | } 70 | 71 | inline SNES_SPC::Timer* SNES_SPC::run_timer( Timer* t, rel_time_t time ) 72 | { 73 | if ( time >= t->next_time ) 74 | t = run_timer_( t, time ); 75 | return t; 76 | } 77 | 78 | 79 | //// ROM 80 | 81 | void SNES_SPC::enable_rom( int enable ) 82 | { 83 | if ( m.rom_enabled != enable ) 84 | { 85 | m.rom_enabled = enable; 86 | if ( enable ) 87 | memcpy( m.hi_ram, &RAM [rom_addr], sizeof m.hi_ram ); 88 | memcpy( &RAM [rom_addr], (enable ? m.rom : m.hi_ram), rom_size ); 89 | // TODO: ROM can still get overwritten when DSP writes to echo buffer 90 | } 91 | } 92 | 93 | 94 | //// DSP 95 | 96 | #if SPC_LESS_ACCURATE 97 | int const max_reg_time = 29; 98 | 99 | signed char const SNES_SPC::reg_times_ [256] = 100 | { 101 | -1, 0,-11,-10,-15,-11, -2, -2, 4, 3, 14, 14, 26, 26, 14, 22, 102 | 2, 3, 0, 1,-12, 0, 1, 1, 7, 6, 14, 14, 27, 14, 14, 23, 103 | 5, 6, 3, 4, -1, 3, 4, 4, 10, 9, 14, 14, 26, -5, 14, 23, 104 | 8, 9, 6, 7, 2, 6, 7, 7, 13, 12, 14, 14, 27, -4, 14, 24, 105 | 11, 12, 9, 10, 5, 9, 10, 10, 16, 15, 14, 14, -2, -4, 14, 24, 106 | 14, 15, 12, 13, 8, 12, 13, 13, 19, 18, 14, 14, -2,-36, 14, 24, 107 | 17, 18, 15, 16, 11, 15, 16, 16, 22, 21, 14, 14, 28, -3, 14, 25, 108 | 20, 21, 18, 19, 14, 18, 19, 19, 25, 24, 14, 14, 14, 29, 14, 25, 109 | 110 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 111 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 112 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 113 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 114 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 115 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 116 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 117 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 118 | }; 119 | 120 | #define RUN_DSP( time, offset ) \ 121 | int count = (time) - (offset) - m.dsp_time;\ 122 | if ( count >= 0 )\ 123 | {\ 124 | int clock_count = (count & ~(clocks_per_sample - 1)) + clocks_per_sample;\ 125 | m.dsp_time += clock_count;\ 126 | dsp.run( clock_count );\ 127 | } 128 | #else 129 | #define RUN_DSP( time, offset ) \ 130 | {\ 131 | int count = (time) - m.dsp_time;\ 132 | if ( !SPC_MORE_ACCURACY || count )\ 133 | {\ 134 | assert( count > 0 );\ 135 | m.dsp_time = (time);\ 136 | dsp.run( count );\ 137 | }\ 138 | } 139 | #endif 140 | 141 | int SNES_SPC::dsp_read( rel_time_t time ) 142 | { 143 | RUN_DSP( time, reg_times [REGS [r_dspaddr] & 0x7F] ); 144 | 145 | int result = dsp.read( REGS [r_dspaddr] & 0x7F ); 146 | 147 | #ifdef SPC_DSP_READ_HOOK 148 | SPC_DSP_READ_HOOK( spc_time + time, (REGS [r_dspaddr] & 0x7F), result ); 149 | #endif 150 | 151 | return result; 152 | } 153 | 154 | inline void SNES_SPC::dsp_write( int data, rel_time_t time ) 155 | { 156 | RUN_DSP( time, reg_times [REGS [r_dspaddr]] ) 157 | #if SPC_LESS_ACCURATE 158 | else if ( m.dsp_time == skipping_time ) 159 | { 160 | int r = REGS [r_dspaddr]; 161 | if ( r == SPC_DSP::r_kon ) 162 | m.skipped_kon |= data & ~dsp.read( SPC_DSP::r_koff ); 163 | 164 | if ( r == SPC_DSP::r_koff ) 165 | { 166 | m.skipped_koff |= data; 167 | m.skipped_kon &= ~data; 168 | } 169 | } 170 | #endif 171 | 172 | #ifdef SPC_DSP_WRITE_HOOK 173 | SPC_DSP_WRITE_HOOK( m.spc_time + time, REGS [r_dspaddr], (uint8_t) data ); 174 | #endif 175 | 176 | if ( REGS [r_dspaddr] <= 0x7F ) 177 | dsp.write( REGS [r_dspaddr], data ); 178 | else if ( !SPC_MORE_ACCURACY ) 179 | dprintf( "SPC wrote to DSP register > $7F\n" ); 180 | } 181 | 182 | 183 | //// Memory access extras 184 | 185 | #if SPC_MORE_ACCURACY 186 | #define MEM_ACCESS( time, addr ) \ 187 | {\ 188 | if ( time >= m.dsp_time )\ 189 | {\ 190 | RUN_DSP( time, max_reg_time );\ 191 | }\ 192 | } 193 | #elif !defined (NDEBUG) 194 | // Debug-only check for read/write within echo buffer, since this might result in 195 | // inaccurate emulation due to the DSP not being caught up to the present. 196 | 197 | bool SNES_SPC::check_echo_access( int addr ) 198 | { 199 | if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) 200 | { 201 | int start = 0x100 * dsp.read( SPC_DSP::r_esa ); 202 | int size = 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F); 203 | int end = start + (size ? size : 4); 204 | if ( start <= addr && addr < end ) 205 | { 206 | if ( !m.echo_accessed ) 207 | { 208 | m.echo_accessed = 1; 209 | return true; 210 | } 211 | } 212 | } 213 | return false; 214 | } 215 | 216 | #define MEM_ACCESS( time, addr ) check( !check_echo_access( (uint16_t) addr ) ); 217 | #else 218 | #define MEM_ACCESS( time, addr ) 219 | #endif 220 | 221 | 222 | //// CPU write 223 | 224 | #if SPC_MORE_ACCURACY 225 | static unsigned char const glitch_probs [3] [256] = 226 | { 227 | 0xC3,0x92,0x5B,0x1C,0xD1,0x92,0x5B,0x1C,0xDB,0x9C,0x72,0x18,0xCD,0x5C,0x38,0x0B, 228 | 0xE1,0x9C,0x74,0x17,0xCF,0x75,0x45,0x0C,0xCF,0x6E,0x4A,0x0D,0xA3,0x3A,0x1D,0x08, 229 | 0xDB,0xA0,0x82,0x19,0xD9,0x73,0x3C,0x0E,0xCB,0x76,0x52,0x0B,0xA5,0x46,0x1D,0x09, 230 | 0xDA,0x74,0x55,0x0F,0xA2,0x3F,0x21,0x05,0x9A,0x40,0x20,0x07,0x63,0x1E,0x10,0x01, 231 | 0xDF,0xA9,0x85,0x1D,0xD3,0x84,0x4B,0x0E,0xCF,0x6F,0x49,0x0F,0xB3,0x48,0x1E,0x05, 232 | 0xD8,0x77,0x52,0x12,0xB7,0x49,0x23,0x06,0xAA,0x45,0x28,0x07,0x7D,0x28,0x0F,0x07, 233 | 0xCC,0x7B,0x4A,0x0E,0xB2,0x4F,0x24,0x07,0xAD,0x43,0x2C,0x06,0x86,0x29,0x11,0x07, 234 | 0xAE,0x48,0x1F,0x0A,0x76,0x21,0x19,0x05,0x76,0x21,0x14,0x05,0x44,0x11,0x0B,0x01, 235 | 0xE7,0xAD,0x96,0x23,0xDC,0x86,0x59,0x0E,0xDC,0x7C,0x5F,0x15,0xBB,0x53,0x2E,0x09, 236 | 0xD6,0x7C,0x4A,0x16,0xBB,0x4A,0x25,0x08,0xB3,0x4F,0x28,0x0B,0x8E,0x23,0x15,0x08, 237 | 0xCF,0x7F,0x57,0x11,0xB5,0x4A,0x23,0x0A,0xAA,0x42,0x28,0x05,0x7D,0x22,0x12,0x03, 238 | 0xA6,0x49,0x28,0x09,0x82,0x2B,0x0D,0x04,0x7A,0x20,0x0F,0x04,0x3D,0x0F,0x09,0x03, 239 | 0xD1,0x7C,0x4C,0x0F,0xAF,0x4E,0x21,0x09,0xA8,0x46,0x2A,0x07,0x85,0x1F,0x0E,0x07, 240 | 0xA6,0x3F,0x26,0x07,0x7C,0x24,0x14,0x07,0x78,0x22,0x16,0x04,0x46,0x12,0x0A,0x02, 241 | 0xA6,0x41,0x2C,0x0A,0x7E,0x28,0x11,0x05,0x73,0x1B,0x14,0x05,0x3D,0x11,0x0A,0x02, 242 | 0x70,0x22,0x17,0x05,0x48,0x13,0x08,0x03,0x3C,0x07,0x0D,0x07,0x26,0x07,0x06,0x01, 243 | 244 | 0xE0,0x9F,0xDA,0x7C,0x4F,0x18,0x28,0x0D,0xE9,0x9F,0xDA,0x7C,0x4F,0x18,0x1F,0x07, 245 | 0xE6,0x97,0xD8,0x72,0x64,0x13,0x26,0x09,0xDC,0x67,0xA9,0x38,0x21,0x07,0x15,0x06, 246 | 0xE9,0x91,0xD2,0x6B,0x63,0x14,0x2B,0x0E,0xD6,0x61,0xB7,0x41,0x2B,0x0E,0x10,0x09, 247 | 0xCF,0x59,0xB0,0x2F,0x35,0x08,0x0F,0x07,0xB6,0x30,0x7A,0x21,0x17,0x07,0x09,0x03, 248 | 0xE7,0xA3,0xE5,0x6B,0x65,0x1F,0x34,0x09,0xD8,0x6B,0xBE,0x45,0x27,0x07,0x10,0x07, 249 | 0xDA,0x54,0xB1,0x39,0x2E,0x0E,0x17,0x08,0xA9,0x3C,0x86,0x22,0x16,0x06,0x07,0x03, 250 | 0xD4,0x51,0xBC,0x3D,0x38,0x0A,0x13,0x06,0xB2,0x37,0x79,0x1C,0x17,0x05,0x0E,0x06, 251 | 0xA7,0x31,0x74,0x1C,0x11,0x06,0x0C,0x02,0x6D,0x1A,0x38,0x10,0x0B,0x05,0x06,0x03, 252 | 0xEB,0x9A,0xE1,0x7A,0x6F,0x13,0x34,0x0E,0xE6,0x75,0xC5,0x45,0x3E,0x0B,0x1A,0x05, 253 | 0xD8,0x63,0xC1,0x40,0x3C,0x1B,0x19,0x06,0xB3,0x42,0x83,0x29,0x18,0x0A,0x08,0x04, 254 | 0xD4,0x58,0xBA,0x43,0x3F,0x0A,0x1F,0x09,0xB1,0x33,0x8A,0x1F,0x1F,0x06,0x0D,0x05, 255 | 0xAF,0x3C,0x7A,0x1F,0x16,0x08,0x0A,0x01,0x72,0x1B,0x52,0x0D,0x0B,0x09,0x06,0x01, 256 | 0xCF,0x63,0xB7,0x47,0x40,0x10,0x14,0x06,0xC0,0x41,0x96,0x20,0x1C,0x09,0x10,0x05, 257 | 0xA6,0x35,0x82,0x1A,0x20,0x0C,0x0E,0x04,0x80,0x1F,0x53,0x0F,0x0B,0x02,0x06,0x01, 258 | 0xA6,0x31,0x81,0x1B,0x1D,0x01,0x08,0x08,0x7B,0x20,0x4D,0x19,0x0E,0x05,0x07,0x03, 259 | 0x6B,0x17,0x49,0x07,0x0E,0x03,0x0A,0x05,0x37,0x0B,0x1F,0x06,0x04,0x02,0x07,0x01, 260 | 261 | 0xF0,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x47,0x1E,0x6E,0x1B,0x32,0x0A, 262 | 0xF0,0xD6,0xEA,0xA4,0xED,0xC4,0xDE,0x82,0x98,0x1F,0x50,0x13,0x52,0x15,0x2A,0x0A, 263 | 0xF1,0xD1,0xEB,0xA2,0xEB,0xB7,0xD8,0x69,0xA2,0x1F,0x5B,0x18,0x55,0x18,0x2C,0x0A, 264 | 0xED,0xB5,0xDE,0x7E,0xE6,0x85,0xD3,0x59,0x59,0x0F,0x2C,0x09,0x24,0x07,0x15,0x09, 265 | 0xF1,0xD6,0xEA,0xA0,0xEC,0xBB,0xDA,0x77,0xA9,0x23,0x58,0x14,0x5D,0x12,0x2F,0x09, 266 | 0xF1,0xC1,0xE3,0x86,0xE4,0x87,0xD2,0x4E,0x68,0x15,0x26,0x0B,0x27,0x09,0x15,0x02, 267 | 0xEE,0xA6,0xE0,0x5C,0xE0,0x77,0xC3,0x41,0x67,0x1B,0x3C,0x07,0x2A,0x06,0x19,0x07, 268 | 0xE4,0x75,0xC6,0x43,0xCC,0x50,0x95,0x23,0x35,0x09,0x14,0x04,0x15,0x05,0x0B,0x04, 269 | 0xEE,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x56,0x14,0x5A,0x12,0x26,0x0A, 270 | 0xEE,0xBB,0xE7,0x7E,0xE9,0x8D,0xCB,0x49,0x67,0x11,0x34,0x07,0x2B,0x0B,0x14,0x07, 271 | 0xED,0xA7,0xE5,0x76,0xE3,0x7E,0xC4,0x4B,0x77,0x14,0x34,0x08,0x27,0x07,0x14,0x04, 272 | 0xE7,0x8B,0xD2,0x4C,0xCA,0x56,0x9E,0x31,0x36,0x0C,0x11,0x07,0x14,0x04,0x0A,0x02, 273 | 0xF0,0x9B,0xEA,0x6F,0xE5,0x81,0xC4,0x43,0x74,0x10,0x30,0x0B,0x2D,0x08,0x1B,0x06, 274 | 0xE6,0x83,0xCA,0x48,0xD9,0x56,0xA7,0x23,0x3B,0x09,0x12,0x09,0x15,0x07,0x0A,0x03, 275 | 0xE5,0x5F,0xCB,0x3C,0xCF,0x48,0x91,0x22,0x31,0x0A,0x17,0x08,0x15,0x04,0x0D,0x02, 276 | 0xD1,0x43,0x91,0x20,0xA9,0x2D,0x54,0x12,0x17,0x07,0x09,0x02,0x0C,0x04,0x05,0x03, 277 | }; 278 | #endif 279 | 280 | // divided into multiple functions to keep rarely-used functionality separate 281 | // so often-used functionality can be optimized better by compiler 282 | 283 | // If write isn't preceded by read, data has this added to it 284 | int const no_read_before_write = 0x2000; 285 | 286 | void SNES_SPC::cpu_write_smp_reg_( int data, rel_time_t time, int addr ) 287 | { 288 | switch ( addr ) 289 | { 290 | case r_t0target: 291 | case r_t1target: 292 | case r_t2target: { 293 | Timer* t = &m.timers [addr - r_t0target]; 294 | int period = IF_0_THEN_256( data ); 295 | if ( t->period != period ) 296 | { 297 | t = run_timer( t, time ); 298 | #if SPC_MORE_ACCURACY 299 | // Insane behavior when target is written just after counter is 300 | // clocked and counter matches new period and new period isn't 1, 2, 4, or 8 301 | if ( t->divider == (period & 0xFF) && 302 | t->next_time == time + TIMER_MUL( t, 1 ) && 303 | ((period - 1) | ~0x0F) & period ) 304 | { 305 | //dprintf( "SPC pathological timer target write\n" ); 306 | 307 | // If the period is 3, 5, or 9, there's a probability this behavior won't occur, 308 | // based on the previous period 309 | int prob = 0xFF; 310 | int old_period = t->period & 0xFF; 311 | if ( period == 3 ) prob = glitch_probs [0] [old_period]; 312 | if ( period == 5 ) prob = glitch_probs [1] [old_period]; 313 | if ( period == 9 ) prob = glitch_probs [2] [old_period]; 314 | 315 | // The glitch suppresses incrementing of one of the counter bits, based on 316 | // the lowest set bit in the new period 317 | int b = 1; 318 | while ( !(period & b) ) 319 | b <<= 1; 320 | 321 | if ( (rand() >> 4 & 0xFF) <= prob ) 322 | t->divider = (t->divider - b) & 0xFF; 323 | } 324 | #endif 325 | t->period = period; 326 | } 327 | break; 328 | } 329 | 330 | case r_t0out: 331 | case r_t1out: 332 | case r_t2out: 333 | if ( !SPC_MORE_ACCURACY ) 334 | dprintf( "SPC wrote to counter %d\n", (int) addr - r_t0out ); 335 | 336 | if ( data < no_read_before_write / 2 ) 337 | run_timer( &m.timers [addr - r_t0out], time - 1 )->counter = 0; 338 | break; 339 | 340 | // Registers that act like RAM 341 | case 0x8: 342 | case 0x9: 343 | REGS_IN [addr] = (uint8_t) data; 344 | break; 345 | 346 | case r_test: 347 | if ( (uint8_t) data != 0x0A ) 348 | dprintf( "SPC wrote to test register\n" ); 349 | break; 350 | 351 | case r_control: 352 | // port clears 353 | if ( data & 0x10 ) 354 | { 355 | REGS_IN [r_cpuio0] = 0; 356 | REGS_IN [r_cpuio1] = 0; 357 | } 358 | if ( data & 0x20 ) 359 | { 360 | REGS_IN [r_cpuio2] = 0; 361 | REGS_IN [r_cpuio3] = 0; 362 | } 363 | 364 | // timers 365 | { 366 | for ( int i = 0; i < timer_count; i++ ) 367 | { 368 | Timer* t = &m.timers [i]; 369 | int enabled = data >> i & 1; 370 | if ( t->enabled != enabled ) 371 | { 372 | t = run_timer( t, time ); 373 | t->enabled = enabled; 374 | if ( enabled ) 375 | { 376 | t->divider = 0; 377 | t->counter = 0; 378 | } 379 | } 380 | } 381 | } 382 | enable_rom( data & 0x80 ); 383 | break; 384 | } 385 | } 386 | 387 | void SNES_SPC::cpu_write_smp_reg( int data, rel_time_t time, int addr ) 388 | { 389 | if ( addr == r_dspdata ) // 99% 390 | dsp_write( data, time ); 391 | else 392 | cpu_write_smp_reg_( data, time, addr ); 393 | } 394 | 395 | void SNES_SPC::cpu_write_high( int data, int i, rel_time_t time ) 396 | { 397 | if ( i < rom_size ) 398 | { 399 | m.hi_ram [i] = (uint8_t) data; 400 | if ( m.rom_enabled ) 401 | RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM 402 | } 403 | else 404 | { 405 | assert( RAM [i + rom_addr] == (uint8_t) data ); 406 | RAM [i + rom_addr] = cpu_pad_fill; // restore overwritten padding 407 | cpu_write( data, i + rom_addr - 0x10000, time ); 408 | } 409 | } 410 | 411 | int const bits_in_int = CHAR_BIT * sizeof (int); 412 | 413 | void SNES_SPC::cpu_write( int data, int addr, rel_time_t time ) 414 | { 415 | MEM_ACCESS( time, addr ) 416 | 417 | // RAM 418 | RAM [addr] = (uint8_t) data; 419 | int reg = addr - 0xF0; 420 | if ( reg >= 0 ) // 64% 421 | { 422 | // $F0-$FF 423 | if ( reg < reg_count ) // 87% 424 | { 425 | REGS [reg] = (uint8_t) data; 426 | 427 | // Ports 428 | #ifdef SPC_PORT_WRITE_HOOK 429 | if ( (unsigned) (reg - r_cpuio0) < port_count ) 430 | SPC_PORT_WRITE_HOOK( m.spc_time + time, (reg - r_cpuio0), 431 | (uint8_t) data, ®S [r_cpuio0] ); 432 | #endif 433 | 434 | // Registers other than $F2 and $F4-$F7 435 | //if ( reg != 2 && reg != 4 && reg != 5 && reg != 6 && reg != 7 ) 436 | // TODO: this is a bit on the fragile side 437 | if ( ((~0x2F00 << (bits_in_int - 16)) << reg) < 0 ) // 36% 438 | cpu_write_smp_reg( data, time, reg ); 439 | } 440 | // High mem/address wrap-around 441 | else 442 | { 443 | reg -= rom_addr - 0xF0; 444 | if ( reg >= 0 ) // 1% in IPL ROM area or address wrapped around 445 | cpu_write_high( data, reg, time ); 446 | } 447 | } 448 | } 449 | 450 | 451 | //// CPU read 452 | 453 | inline int SNES_SPC::cpu_read_smp_reg( int reg, rel_time_t time ) 454 | { 455 | int result = REGS_IN [reg]; 456 | reg -= r_dspaddr; 457 | // DSP addr and data 458 | if ( (unsigned) reg <= 1 ) // 4% 0xF2 and 0xF3 459 | { 460 | result = REGS [r_dspaddr]; 461 | if ( (unsigned) reg == 1 ) 462 | result = dsp_read( time ); // 0xF3 463 | } 464 | return result; 465 | } 466 | 467 | int SNES_SPC::cpu_read( int addr, rel_time_t time ) 468 | { 469 | MEM_ACCESS( time, addr ) 470 | 471 | // RAM 472 | int result = RAM [addr]; 473 | int reg = addr - 0xF0; 474 | if ( reg >= 0 ) // 40% 475 | { 476 | reg -= 0x10; 477 | if ( (unsigned) reg >= 0xFF00 ) // 21% 478 | { 479 | reg += 0x10 - r_t0out; 480 | 481 | // Timers 482 | if ( (unsigned) reg < timer_count ) // 90% 483 | { 484 | Timer* t = &m.timers [reg]; 485 | if ( time >= t->next_time ) 486 | t = run_timer_( t, time ); 487 | result = t->counter; 488 | t->counter = 0; 489 | } 490 | // Other registers 491 | else if ( reg < 0 ) // 10% 492 | { 493 | result = cpu_read_smp_reg( reg + r_t0out, time ); 494 | } 495 | else // 1% 496 | { 497 | assert( reg + (r_t0out + 0xF0 - 0x10000) < 0x100 ); 498 | result = cpu_read( reg + (r_t0out + 0xF0 - 0x10000), time ); 499 | } 500 | } 501 | } 502 | 503 | return result; 504 | } 505 | 506 | 507 | //// Run 508 | 509 | // Prefix and suffix for CPU emulator function 510 | #define SPC_CPU_RUN_FUNC \ 511 | BOOST::uint8_t* SNES_SPC::run_until_( time_t end_time )\ 512 | {\ 513 | rel_time_t rel_time = m.spc_time - end_time;\ 514 | assert( rel_time <= 0 );\ 515 | m.spc_time = end_time;\ 516 | m.dsp_time += rel_time;\ 517 | m.timers [0].next_time += rel_time;\ 518 | m.timers [1].next_time += rel_time;\ 519 | m.timers [2].next_time += rel_time; 520 | 521 | #define SPC_CPU_RUN_FUNC_END \ 522 | m.spc_time += rel_time;\ 523 | m.dsp_time -= rel_time;\ 524 | m.timers [0].next_time -= rel_time;\ 525 | m.timers [1].next_time -= rel_time;\ 526 | m.timers [2].next_time -= rel_time;\ 527 | assert( m.spc_time <= end_time );\ 528 | return ®S [r_cpuio0];\ 529 | } 530 | 531 | int const cpu_lag_max = 12 - 1; // DIV YA,X takes 12 clocks 532 | 533 | void SNES_SPC::end_frame( time_t end_time ) 534 | { 535 | // Catch CPU up to as close to end as possible. If final instruction 536 | // would exceed end, does NOT execute it and leaves m.spc_time < end. 537 | if ( end_time > m.spc_time ) 538 | run_until_( end_time ); 539 | 540 | m.spc_time -= end_time; 541 | m.extra_clocks += end_time; 542 | 543 | // Greatest number of clocks early that emulation can stop early due to 544 | // not being able to execute current instruction without going over 545 | // allowed time. 546 | assert( -cpu_lag_max <= m.spc_time && m.spc_time <= 0 ); 547 | 548 | // Catch timers up to CPU 549 | for ( int i = 0; i < timer_count; i++ ) 550 | run_timer( &m.timers [i], 0 ); 551 | 552 | // Catch DSP up to CPU 553 | if ( m.dsp_time < 0 ) 554 | { 555 | RUN_DSP( 0, max_reg_time ); 556 | } 557 | 558 | // Save any extra samples beyond what should be generated 559 | if ( m.buf_begin ) 560 | save_extra(); 561 | } 562 | 563 | // Inclusion here allows static memory access functions and better optimization 564 | #include "SPC_CPU.h" 565 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/SNES_SPC.h: -------------------------------------------------------------------------------- 1 | // SNES SPC-700 APU emulator 2 | 3 | // snes_spc 0.9.0 4 | #ifndef SNES_SPC_H 5 | #define SNES_SPC_H 6 | 7 | #include "SPC_DSP.h" 8 | #include "blargg_endian.h" 9 | 10 | struct SNES_SPC { 11 | public: 12 | typedef BOOST::uint8_t uint8_t; 13 | 14 | // Must be called once before using 15 | blargg_err_t init(); 16 | 17 | // Sample pairs generated per second 18 | enum { sample_rate = 32000 }; 19 | 20 | // Emulator use 21 | 22 | // Sets IPL ROM data. Library does not include ROM data. Most SPC music files 23 | // don't need ROM, but a full emulator must provide this. 24 | enum { rom_size = 0x40 }; 25 | void init_rom( uint8_t const rom [rom_size] ); 26 | 27 | // Sets destination for output samples 28 | typedef short sample_t; 29 | void set_output( sample_t* out, int out_size ); 30 | 31 | // Number of samples written to output since last set 32 | int sample_count() const; 33 | 34 | // Resets SPC to power-on state. This resets your output buffer, so you must 35 | // call set_output() after this. 36 | void reset(); 37 | 38 | // Emulates pressing reset switch on SNES. This resets your output buffer, so 39 | // you must call set_output() after this. 40 | void soft_reset(); 41 | 42 | // 1024000 SPC clocks per second, sample pair every 32 clocks 43 | typedef int time_t; 44 | enum { clock_rate = 1024000 }; 45 | enum { clocks_per_sample = 32 }; 46 | 47 | // Emulated port read/write at specified time 48 | enum { port_count = 4 }; 49 | int read_port ( time_t, int port ); 50 | void write_port( time_t, int port, int data ); 51 | 52 | // Runs SPC to end_time and starts a new time frame at 0 53 | void end_frame( time_t end_time ); 54 | 55 | // Sound control 56 | 57 | // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). 58 | // Reduces emulation accuracy. 59 | enum { voice_count = 8 }; 60 | void mute_voices( int mask ); 61 | 62 | // If true, prevents channels and global volumes from being phase-negated. 63 | // Only supported by fast DSP. 64 | void disable_surround( bool disable = true ); 65 | 66 | // Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc. 67 | enum { tempo_unit = 0x100 }; 68 | void set_tempo( int ); 69 | 70 | // SPC music files 71 | 72 | // Loads SPC data into emulator 73 | enum { spc_min_file_size = 0x10180 }; 74 | enum { spc_file_size = 0x10200 }; 75 | blargg_err_t load_spc( void const* in, long size ); 76 | 77 | // Clears echo region. Useful after loading an SPC as many have garbage in echo. 78 | void clear_echo(); 79 | 80 | // Plays for count samples and write samples to out. Discards samples if out 81 | // is NULL. Count must be a multiple of 2 since output is stereo. 82 | blargg_err_t play( int count, sample_t* out ); 83 | 84 | // Skips count samples. Several times faster than play() when using fast DSP. 85 | blargg_err_t skip( int count ); 86 | 87 | // State save/load (only available with accurate DSP) 88 | 89 | #if !SPC_NO_COPY_STATE_FUNCS 90 | // Saves/loads state 91 | enum { state_size = 67 * 1024L }; // maximum space needed when saving 92 | typedef SPC_DSP::copy_func_t copy_func_t; 93 | void copy_state( unsigned char** io, copy_func_t ); 94 | 95 | // Writes minimal header to spc_out 96 | static void init_header( void* spc_out ); 97 | 98 | // Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. 99 | // Does not set up SPC header; use init_header() for that. 100 | void save_spc( void* spc_out ); 101 | 102 | // Returns true if new key-on events occurred since last check. Useful for 103 | // trimming silence while saving an SPC. 104 | bool check_kon(); 105 | #endif 106 | 107 | public: 108 | BLARGG_DISABLE_NOTHROW 109 | 110 | typedef BOOST::uint16_t uint16_t; 111 | 112 | // Time relative to m_spc_time. Speeds up code a bit by eliminating need to 113 | // constantly add m_spc_time to time from CPU. CPU uses time that ends at 114 | // 0 to eliminate reloading end time every instruction. It pays off. 115 | typedef int rel_time_t; 116 | 117 | struct Timer 118 | { 119 | rel_time_t next_time; // time of next event 120 | int prescaler; 121 | int period; 122 | int divider; 123 | int enabled; 124 | int counter; 125 | }; 126 | enum { reg_count = 0x10 }; 127 | enum { timer_count = 3 }; 128 | enum { extra_size = SPC_DSP::extra_size }; 129 | 130 | enum { signature_size = 35 }; 131 | 132 | private: 133 | SPC_DSP dsp; 134 | 135 | #if SPC_LESS_ACCURATE 136 | static signed char const reg_times_ [256]; 137 | signed char reg_times [256]; 138 | #endif 139 | 140 | struct state_t 141 | { 142 | Timer timers [timer_count]; 143 | 144 | uint8_t smp_regs [2] [reg_count]; 145 | 146 | struct 147 | { 148 | int pc; 149 | int a; 150 | int x; 151 | int y; 152 | int psw; 153 | int sp; 154 | } cpu_regs; 155 | 156 | rel_time_t dsp_time; 157 | time_t spc_time; 158 | bool echo_accessed; 159 | 160 | int tempo; 161 | int skipped_kon; 162 | int skipped_koff; 163 | const char* cpu_error; 164 | 165 | int extra_clocks; 166 | sample_t* buf_begin; 167 | sample_t const* buf_end; 168 | sample_t* extra_pos; 169 | sample_t extra_buf [extra_size]; 170 | 171 | int rom_enabled; 172 | uint8_t rom [rom_size]; 173 | uint8_t hi_ram [rom_size]; 174 | 175 | unsigned char cycle_table [256]; 176 | 177 | struct 178 | { 179 | // padding to neutralize address overflow 180 | union { 181 | uint8_t padding1 [0x100]; 182 | uint16_t align; // makes compiler align data for 16-bit access 183 | } padding1 [1]; 184 | uint8_t ram [0x10000]; 185 | uint8_t padding2 [0x100]; 186 | } ram; 187 | }; 188 | state_t m; 189 | 190 | enum { rom_addr = 0xFFC0 }; 191 | 192 | enum { skipping_time = 127 }; 193 | 194 | // Value that padding should be filled with 195 | enum { cpu_pad_fill = 0xFF }; 196 | 197 | enum { 198 | r_test = 0x0, r_control = 0x1, 199 | r_dspaddr = 0x2, r_dspdata = 0x3, 200 | r_cpuio0 = 0x4, r_cpuio1 = 0x5, 201 | r_cpuio2 = 0x6, r_cpuio3 = 0x7, 202 | r_f8 = 0x8, r_f9 = 0x9, 203 | r_t0target = 0xA, r_t1target = 0xB, r_t2target = 0xC, 204 | r_t0out = 0xD, r_t1out = 0xE, r_t2out = 0xF 205 | }; 206 | 207 | void timers_loaded(); 208 | void enable_rom( int enable ); 209 | void reset_buf(); 210 | void save_extra(); 211 | void load_regs( uint8_t const in [reg_count] ); 212 | void ram_loaded(); 213 | void regs_loaded(); 214 | void reset_time_regs(); 215 | void reset_common( int timer_counter_init ); 216 | 217 | Timer* run_timer_ ( Timer* t, rel_time_t ); 218 | Timer* run_timer ( Timer* t, rel_time_t ); 219 | int dsp_read ( rel_time_t ); 220 | void dsp_write ( int data, rel_time_t ); 221 | void cpu_write_smp_reg_( int data, rel_time_t, int addr ); 222 | void cpu_write_smp_reg ( int data, rel_time_t, int addr ); 223 | void cpu_write_high ( int data, int i, rel_time_t ); 224 | void cpu_write ( int data, int addr, rel_time_t ); 225 | int cpu_read_smp_reg ( int i, rel_time_t ); 226 | int cpu_read ( int addr, rel_time_t ); 227 | unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t ); 228 | 229 | bool check_echo_access ( int addr ); 230 | uint8_t* run_until_( time_t end_time ); 231 | 232 | struct spc_file_t 233 | { 234 | char signature [signature_size]; 235 | uint8_t has_id666; 236 | uint8_t version; 237 | uint8_t pcl, pch; 238 | uint8_t a; 239 | uint8_t x; 240 | uint8_t y; 241 | uint8_t psw; 242 | uint8_t sp; 243 | char text [212]; 244 | uint8_t ram [0x10000]; 245 | uint8_t dsp [128]; 246 | uint8_t unused [0x40]; 247 | uint8_t ipl_rom [0x40]; 248 | }; 249 | 250 | static char const signature [signature_size + 1]; 251 | 252 | void save_regs( uint8_t out [reg_count] ); 253 | }; 254 | 255 | #include 256 | 257 | inline int SNES_SPC::sample_count() const { return (m.extra_clocks >> 5) * 2; } 258 | 259 | inline int SNES_SPC::read_port( time_t t, int port ) 260 | { 261 | assert( (unsigned) port < port_count ); 262 | return run_until_( t ) [port]; 263 | } 264 | 265 | inline void SNES_SPC::write_port( time_t t, int port, int data ) 266 | { 267 | assert( (unsigned) port < port_count ); 268 | run_until_( t ) [0x10 + port] = data; 269 | } 270 | 271 | inline void SNES_SPC::mute_voices( int mask ) { dsp.mute_voices( mask ); } 272 | 273 | inline void SNES_SPC::disable_surround( bool disable ) { dsp.disable_surround( disable ); } 274 | 275 | #if !SPC_NO_COPY_STATE_FUNCS 276 | inline bool SNES_SPC::check_kon() { return dsp.check_kon(); } 277 | #endif 278 | 279 | #endif 280 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/SNES_SPC_misc.cpp: -------------------------------------------------------------------------------- 1 | // SPC emulation support: init, sample buffering, reset, SPC loading 2 | 3 | // snes_spc 0.9.0. http://www.slack.net/~ant/ 4 | 5 | #include "SNES_SPC.h" 6 | 7 | #include 8 | 9 | /* Copyright (C) 2004-2007 Shay Green. This module is free software; you 10 | can redistribute it and/or modify it under the terms of the GNU Lesser 11 | General Public License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. This 13 | module is distributed in the hope that it will be useful, but WITHOUT ANY 14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 16 | details. You should have received a copy of the GNU Lesser General Public 17 | License along with this module; if not, write to the Free Software Foundation, 18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 19 | 20 | #include "blargg_source.h" 21 | 22 | #define RAM (m.ram.ram) 23 | #define REGS (m.smp_regs [0]) 24 | #define REGS_IN (m.smp_regs [1]) 25 | 26 | // (n ? n : 256) 27 | #define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) 28 | 29 | 30 | //// Init 31 | 32 | blargg_err_t SNES_SPC::init() 33 | { 34 | memset( &m, 0, sizeof m ); 35 | dsp.init( RAM ); 36 | 37 | m.tempo = tempo_unit; 38 | 39 | // Most SPC music doesn't need ROM, and almost all the rest only rely 40 | // on these two bytes 41 | m.rom [0x3E] = 0xFF; 42 | m.rom [0x3F] = 0xC0; 43 | 44 | static unsigned char const cycle_table [128] = 45 | {// 01 23 45 67 89 AB CD EF 46 | 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x68, // 0 47 | 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x46, // 1 48 | 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x74, // 2 49 | 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x38, // 3 50 | 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x66, // 4 51 | 0x48,0x47,0x45,0x56,0x55,0x45,0x22,0x43, // 5 52 | 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x75, // 6 53 | 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x36, // 7 54 | 0x28,0x47,0x34,0x36,0x26,0x54,0x52,0x45, // 8 55 | 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0xC5, // 9 56 | 0x38,0x47,0x34,0x36,0x26,0x44,0x52,0x44, // A 57 | 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x34, // B 58 | 0x38,0x47,0x45,0x47,0x25,0x64,0x52,0x49, // C 59 | 0x48,0x47,0x56,0x67,0x45,0x55,0x22,0x83, // D 60 | 0x28,0x47,0x34,0x36,0x24,0x53,0x43,0x40, // E 61 | 0x48,0x47,0x45,0x56,0x34,0x54,0x22,0x60, // F 62 | }; 63 | 64 | // unpack cycle table 65 | for ( int i = 0; i < 128; i++ ) 66 | { 67 | int n = cycle_table [i]; 68 | m.cycle_table [i * 2 + 0] = n >> 4; 69 | m.cycle_table [i * 2 + 1] = n & 0x0F; 70 | } 71 | 72 | #if SPC_LESS_ACCURATE 73 | memcpy( reg_times, reg_times_, sizeof reg_times ); 74 | #endif 75 | 76 | reset(); 77 | return 0; 78 | } 79 | 80 | void SNES_SPC::init_rom( uint8_t const in [rom_size] ) 81 | { 82 | memcpy( m.rom, in, sizeof m.rom ); 83 | } 84 | 85 | void SNES_SPC::set_tempo( int t ) 86 | { 87 | m.tempo = t; 88 | int const timer2_shift = 4; // 64 kHz 89 | int const other_shift = 3; // 8 kHz 90 | 91 | #if SPC_DISABLE_TEMPO 92 | m.timers [2].prescaler = timer2_shift; 93 | m.timers [1].prescaler = timer2_shift + other_shift; 94 | m.timers [0].prescaler = timer2_shift + other_shift; 95 | #else 96 | if ( !t ) 97 | t = 1; 98 | int const timer2_rate = 1 << timer2_shift; 99 | int rate = (timer2_rate * tempo_unit + (t >> 1)) / t; 100 | if ( rate < timer2_rate / 4 ) 101 | rate = timer2_rate / 4; // max 4x tempo 102 | m.timers [2].prescaler = rate; 103 | m.timers [1].prescaler = rate << other_shift; 104 | m.timers [0].prescaler = rate << other_shift; 105 | #endif 106 | } 107 | 108 | // Timer registers have been loaded. Applies these to the timers. Does not 109 | // reset timer prescalers or dividers. 110 | void SNES_SPC::timers_loaded() 111 | { 112 | int i; 113 | for ( i = 0; i < timer_count; i++ ) 114 | { 115 | Timer* t = &m.timers [i]; 116 | t->period = IF_0_THEN_256( REGS [r_t0target + i] ); 117 | t->enabled = REGS [r_control] >> i & 1; 118 | t->counter = REGS_IN [r_t0out + i] & 0x0F; 119 | } 120 | 121 | set_tempo( m.tempo ); 122 | } 123 | 124 | // Loads registers from unified 16-byte format 125 | void SNES_SPC::load_regs( uint8_t const in [reg_count] ) 126 | { 127 | memcpy( REGS, in, reg_count ); 128 | memcpy( REGS_IN, REGS, reg_count ); 129 | 130 | // These always read back as 0 131 | REGS_IN [r_test ] = 0; 132 | REGS_IN [r_control ] = 0; 133 | REGS_IN [r_t0target] = 0; 134 | REGS_IN [r_t1target] = 0; 135 | REGS_IN [r_t2target] = 0; 136 | } 137 | 138 | // RAM was just loaded from SPC, with $F0-$FF containing SMP registers 139 | // and timer counts. Copies these to proper registers. 140 | void SNES_SPC::ram_loaded() 141 | { 142 | m.rom_enabled = 0; 143 | load_regs( &RAM [0xF0] ); 144 | 145 | // Put STOP instruction around memory to catch PC underflow/overflow 146 | memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 ); 147 | memset( m.ram.padding2, cpu_pad_fill, sizeof m.ram.padding2 ); 148 | } 149 | 150 | // Registers were just loaded. Applies these new values. 151 | void SNES_SPC::regs_loaded() 152 | { 153 | enable_rom( REGS [r_control] & 0x80 ); 154 | timers_loaded(); 155 | } 156 | 157 | void SNES_SPC::reset_time_regs() 158 | { 159 | m.cpu_error = 0; 160 | m.echo_accessed = 0; 161 | m.spc_time = 0; 162 | m.dsp_time = 0; 163 | #if SPC_LESS_ACCURATE 164 | m.dsp_time = clocks_per_sample + 1; 165 | #endif 166 | 167 | for ( int i = 0; i < timer_count; i++ ) 168 | { 169 | Timer* t = &m.timers [i]; 170 | t->next_time = 1; 171 | t->divider = 0; 172 | } 173 | 174 | regs_loaded(); 175 | 176 | m.extra_clocks = 0; 177 | reset_buf(); 178 | } 179 | 180 | void SNES_SPC::reset_common( int timer_counter_init ) 181 | { 182 | int i; 183 | for ( i = 0; i < timer_count; i++ ) 184 | REGS_IN [r_t0out + i] = timer_counter_init; 185 | 186 | // Run IPL ROM 187 | memset( &m.cpu_regs, 0, sizeof m.cpu_regs ); 188 | m.cpu_regs.pc = rom_addr; 189 | 190 | REGS [r_test ] = 0x0A; 191 | REGS [r_control] = 0xB0; // ROM enabled, clear ports 192 | for ( i = 0; i < port_count; i++ ) 193 | REGS_IN [r_cpuio0 + i] = 0; 194 | 195 | reset_time_regs(); 196 | } 197 | 198 | void SNES_SPC::soft_reset() 199 | { 200 | reset_common( 0 ); 201 | dsp.soft_reset(); 202 | } 203 | 204 | void SNES_SPC::reset() 205 | { 206 | memset( RAM, 0xFF, 0x10000 ); 207 | ram_loaded(); 208 | reset_common( 0x0F ); 209 | dsp.reset(); 210 | } 211 | 212 | char const SNES_SPC::signature [signature_size + 1] = 213 | "SNES-SPC700 Sound File Data v0.30\x1A\x1A"; 214 | 215 | blargg_err_t SNES_SPC::load_spc( void const* data, long size ) 216 | { 217 | spc_file_t const* const spc = (spc_file_t const*) data; 218 | 219 | // be sure compiler didn't insert any padding into fle_t 220 | assert( sizeof (spc_file_t) == spc_min_file_size + 0x80 ); 221 | 222 | // Check signature and file size 223 | if ( size < signature_size || memcmp( spc, signature, 27 ) ) 224 | return "Not an SPC file"; 225 | 226 | if ( size < spc_min_file_size ) 227 | return "Corrupt SPC file"; 228 | 229 | // CPU registers 230 | m.cpu_regs.pc = spc->pch * 0x100 + spc->pcl; 231 | m.cpu_regs.a = spc->a; 232 | m.cpu_regs.x = spc->x; 233 | m.cpu_regs.y = spc->y; 234 | m.cpu_regs.psw = spc->psw; 235 | m.cpu_regs.sp = spc->sp; 236 | 237 | // RAM and registers 238 | memcpy( RAM, spc->ram, 0x10000 ); 239 | ram_loaded(); 240 | 241 | // DSP registers 242 | dsp.load( spc->dsp ); 243 | 244 | reset_time_regs(); 245 | 246 | return 0; 247 | } 248 | 249 | void SNES_SPC::clear_echo() 250 | { 251 | if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) 252 | { 253 | int addr = 0x100 * dsp.read( SPC_DSP::r_esa ); 254 | int end = addr + 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F); 255 | if ( end > 0x10000 ) 256 | end = 0x10000; 257 | memset( &RAM [addr], 0xFF, end - addr ); 258 | } 259 | } 260 | 261 | 262 | //// Sample output 263 | 264 | void SNES_SPC::reset_buf() 265 | { 266 | // Start with half extra buffer of silence 267 | sample_t* out = m.extra_buf; 268 | while ( out < &m.extra_buf [extra_size / 2] ) 269 | *out++ = 0; 270 | 271 | m.extra_pos = out; 272 | m.buf_begin = 0; 273 | 274 | dsp.set_output( 0, 0 ); 275 | } 276 | 277 | void SNES_SPC::set_output( sample_t* out, int size ) 278 | { 279 | require( (size & 1) == 0 ); // size must be even 280 | 281 | m.extra_clocks &= clocks_per_sample - 1; 282 | if ( out ) 283 | { 284 | sample_t const* out_end = out + size; 285 | m.buf_begin = out; 286 | m.buf_end = out_end; 287 | 288 | // Copy extra to output 289 | sample_t const* in = m.extra_buf; 290 | while ( in < m.extra_pos && out < out_end ) 291 | *out++ = *in++; 292 | 293 | // Handle output being full already 294 | if ( out >= out_end ) 295 | { 296 | // Have DSP write to remaining extra space 297 | out = dsp.extra(); 298 | out_end = &dsp.extra() [extra_size]; 299 | 300 | // Copy any remaining extra samples as if DSP wrote them 301 | while ( in < m.extra_pos ) 302 | *out++ = *in++; 303 | assert( out <= out_end ); 304 | } 305 | 306 | dsp.set_output( out, out_end - out ); 307 | } 308 | else 309 | { 310 | reset_buf(); 311 | } 312 | } 313 | 314 | void SNES_SPC::save_extra() 315 | { 316 | // Get end pointers 317 | sample_t const* main_end = m.buf_end; // end of data written to buf 318 | sample_t const* dsp_end = dsp.out_pos(); // end of data written to dsp.extra() 319 | if ( m.buf_begin <= dsp_end && dsp_end <= main_end ) 320 | { 321 | main_end = dsp_end; 322 | dsp_end = dsp.extra(); // nothing in DSP's extra 323 | } 324 | 325 | // Copy any extra samples at these ends into extra_buf 326 | sample_t* out = m.extra_buf; 327 | sample_t const* in; 328 | for ( in = m.buf_begin + sample_count(); in < main_end; in++ ) 329 | *out++ = *in; 330 | for ( in = dsp.extra(); in < dsp_end ; in++ ) 331 | *out++ = *in; 332 | 333 | m.extra_pos = out; 334 | assert( out <= &m.extra_buf [extra_size] ); 335 | } 336 | 337 | blargg_err_t SNES_SPC::play( int count, sample_t* out ) 338 | { 339 | require( (count & 1) == 0 ); // must be even 340 | if ( count ) 341 | { 342 | set_output( out, count ); 343 | end_frame( count * (clocks_per_sample / 2) ); 344 | } 345 | 346 | const char* err = m.cpu_error; 347 | m.cpu_error = 0; 348 | return err; 349 | } 350 | 351 | blargg_err_t SNES_SPC::skip( int count ) 352 | { 353 | #if SPC_LESS_ACCURATE 354 | if ( count > 2 * sample_rate * 2 ) 355 | { 356 | set_output( 0, 0 ); 357 | 358 | // Skip a multiple of 4 samples 359 | time_t end = count; 360 | count = (count & 3) + 1 * sample_rate * 2; 361 | end = (end - count) * (clocks_per_sample / 2); 362 | 363 | m.skipped_kon = 0; 364 | m.skipped_koff = 0; 365 | 366 | // Preserve DSP and timer synchronization 367 | // TODO: verify that this really preserves it 368 | int old_dsp_time = m.dsp_time + m.spc_time; 369 | m.dsp_time = end - m.spc_time + skipping_time; 370 | end_frame( end ); 371 | m.dsp_time = m.dsp_time - skipping_time + old_dsp_time; 372 | 373 | dsp.write( SPC_DSP::r_koff, m.skipped_koff & ~m.skipped_kon ); 374 | dsp.write( SPC_DSP::r_kon , m.skipped_kon ); 375 | clear_echo(); 376 | } 377 | #endif 378 | 379 | return play( count, 0 ); 380 | } 381 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/SNES_SPC_state.cpp: -------------------------------------------------------------------------------- 1 | // SPC emulation state save/load: copy_state(), save_spc() 2 | // Separate file to avoid linking in unless needed 3 | 4 | // snes_spc 0.9.0. http://www.slack.net/~ant/ 5 | 6 | #include "SNES_SPC.h" 7 | 8 | #if !SPC_NO_COPY_STATE_FUNCS 9 | 10 | #include 11 | 12 | /* Copyright (C) 2004-2007 Shay Green. This module is free software; you 13 | can redistribute it and/or modify it under the terms of the GNU Lesser 14 | General Public License as published by the Free Software Foundation; either 15 | version 2.1 of the License, or (at your option) any later version. This 16 | module is distributed in the hope that it will be useful, but WITHOUT ANY 17 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 19 | details. You should have received a copy of the GNU Lesser General Public 20 | License along with this module; if not, write to the Free Software Foundation, 21 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 22 | 23 | #include "blargg_source.h" 24 | 25 | #define RAM (m.ram.ram) 26 | #define REGS (m.smp_regs [0]) 27 | #define REGS_IN (m.smp_regs [1]) 28 | 29 | void SNES_SPC::save_regs( uint8_t out [reg_count] ) 30 | { 31 | // Use current timer counter values 32 | for ( int i = 0; i < timer_count; i++ ) 33 | out [r_t0out + i] = m.timers [i].counter; 34 | 35 | // Last written values 36 | memcpy( out, REGS, r_t0out ); 37 | } 38 | 39 | void SNES_SPC::init_header( void* spc_out ) 40 | { 41 | spc_file_t* const spc = (spc_file_t*) spc_out; 42 | 43 | spc->has_id666 = 26; // has none 44 | spc->version = 30; 45 | memcpy( spc, signature, sizeof spc->signature ); 46 | memset( spc->text, 0, sizeof spc->text ); 47 | } 48 | 49 | void SNES_SPC::save_spc( void* spc_out ) 50 | { 51 | spc_file_t* const spc = (spc_file_t*) spc_out; 52 | 53 | // CPU 54 | spc->pcl = (uint8_t) (m.cpu_regs.pc >> 0); 55 | spc->pch = (uint8_t) (m.cpu_regs.pc >> 8); 56 | spc->a = m.cpu_regs.a; 57 | spc->x = m.cpu_regs.x; 58 | spc->y = m.cpu_regs.y; 59 | spc->psw = m.cpu_regs.psw; 60 | spc->sp = m.cpu_regs.sp; 61 | 62 | // RAM, ROM 63 | memcpy( spc->ram, RAM, sizeof spc->ram ); 64 | if ( m.rom_enabled ) 65 | memcpy( spc->ram + rom_addr, m.hi_ram, sizeof m.hi_ram ); 66 | memset( spc->unused, 0, sizeof spc->unused ); 67 | memcpy( spc->ipl_rom, m.rom, sizeof spc->ipl_rom ); 68 | 69 | // SMP registers 70 | save_regs( &spc->ram [0xF0] ); 71 | int i; 72 | for ( i = 0; i < port_count; i++ ) 73 | spc->ram [0xF0 + r_cpuio0 + i] = REGS_IN [r_cpuio0 + i]; 74 | 75 | // DSP registers 76 | for ( i = 0; i < SPC_DSP::register_count; i++ ) 77 | spc->dsp [i] = dsp.read( i ); 78 | } 79 | 80 | void SNES_SPC::copy_state( unsigned char** io, copy_func_t copy ) 81 | { 82 | SPC_State_Copier copier( io, copy ); 83 | 84 | // Make state data more readable by putting 64K RAM, 16 SMP registers, 85 | // then DSP (with its 128 registers) first 86 | 87 | // RAM 88 | enable_rom( 0 ); // will get re-enabled if necessary in regs_loaded() below 89 | copier.copy( RAM, 0x10000 ); 90 | 91 | { 92 | // SMP registers 93 | uint8_t out_ports [port_count]; 94 | uint8_t regs [reg_count]; 95 | memcpy( out_ports, ®S [r_cpuio0], sizeof out_ports ); 96 | save_regs( regs ); 97 | copier.copy( regs, sizeof regs ); 98 | copier.copy( out_ports, sizeof out_ports ); 99 | load_regs( regs ); 100 | regs_loaded(); 101 | memcpy( ®S [r_cpuio0], out_ports, sizeof out_ports ); 102 | } 103 | 104 | // CPU registers 105 | SPC_COPY( uint16_t, m.cpu_regs.pc ); 106 | SPC_COPY( uint8_t, m.cpu_regs.a ); 107 | SPC_COPY( uint8_t, m.cpu_regs.x ); 108 | SPC_COPY( uint8_t, m.cpu_regs.y ); 109 | SPC_COPY( uint8_t, m.cpu_regs.psw ); 110 | SPC_COPY( uint8_t, m.cpu_regs.sp ); 111 | copier.extra(); 112 | 113 | SPC_COPY( int16_t, m.spc_time ); 114 | SPC_COPY( int16_t, m.dsp_time ); 115 | 116 | // DSP 117 | dsp.copy_state( io, copy ); 118 | 119 | // Timers 120 | for ( int i = 0; i < timer_count; i++ ) 121 | { 122 | Timer* t = &m.timers [i]; 123 | SPC_COPY( int16_t, t->next_time ); 124 | SPC_COPY( uint8_t, t->divider ); 125 | copier.extra(); 126 | } 127 | copier.extra(); 128 | } 129 | #endif 130 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/SPC_DSP.h: -------------------------------------------------------------------------------- 1 | // Fast SNES SPC-700 DSP emulator (about 3x speed of accurate one) 2 | 3 | // snes_spc 0.9.0 4 | #ifndef SPC_DSP_H 5 | #define SPC_DSP_H 6 | 7 | #include "blargg_common.h" 8 | 9 | class SPC_DSP { 10 | public: 11 | typedef BOOST::uint8_t uint8_t; 12 | 13 | // Setup 14 | 15 | // Initializes DSP and has it use the 64K RAM provided 16 | void init( void* ram_64k ); 17 | 18 | // Sets destination for output samples. If out is NULL or out_size is 0, 19 | // doesn't generate any. 20 | typedef short sample_t; 21 | void set_output( sample_t* out, int out_size ); 22 | 23 | // Number of samples written to output since it was last set, always 24 | // a multiple of 2. Undefined if more samples were generated than 25 | // output buffer could hold. 26 | int sample_count() const; 27 | 28 | // Emulation 29 | 30 | // Resets DSP to power-on state 31 | void reset(); 32 | 33 | // Emulates pressing reset switch on SNES 34 | void soft_reset(); 35 | 36 | // Reads/writes DSP registers. For accuracy, you must first call spc_run_dsp() 37 | // to catch the DSP up to present. 38 | int read ( int addr ) const; 39 | void write( int addr, int data ); 40 | 41 | // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks 42 | // a pair of samples is be generated. 43 | void run( int clock_count ); 44 | 45 | // Sound control 46 | 47 | // Mutes voices corresponding to non-zero bits in mask (overrides VxVOL with 0). 48 | // Reduces emulation accuracy. 49 | enum { voice_count = 8 }; 50 | void mute_voices( int mask ); 51 | 52 | // If true, prevents channels and global volumes from being phase-negated 53 | void disable_surround( bool disable = true ); 54 | 55 | // State 56 | 57 | // Resets DSP and uses supplied values to initialize registers 58 | enum { register_count = 128 }; 59 | void load( uint8_t const regs [register_count] ); 60 | 61 | // DSP register addresses 62 | 63 | // Global registers 64 | enum { 65 | r_mvoll = 0x0C, r_mvolr = 0x1C, 66 | r_evoll = 0x2C, r_evolr = 0x3C, 67 | r_kon = 0x4C, r_koff = 0x5C, 68 | r_flg = 0x6C, r_endx = 0x7C, 69 | r_efb = 0x0D, r_pmon = 0x2D, 70 | r_non = 0x3D, r_eon = 0x4D, 71 | r_dir = 0x5D, r_esa = 0x6D, 72 | r_edl = 0x7D, 73 | r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F 74 | }; 75 | 76 | // Voice registers 77 | enum { 78 | v_voll = 0x00, v_volr = 0x01, 79 | v_pitchl = 0x02, v_pitchh = 0x03, 80 | v_srcn = 0x04, v_adsr0 = 0x05, 81 | v_adsr1 = 0x06, v_gain = 0x07, 82 | v_envx = 0x08, v_outx = 0x09 83 | }; 84 | 85 | public: 86 | enum { extra_size = 16 }; 87 | sample_t* extra() { return m.extra; } 88 | sample_t const* out_pos() const { return m.out; } 89 | public: 90 | BLARGG_DISABLE_NOTHROW 91 | 92 | typedef BOOST::int8_t int8_t; 93 | typedef BOOST::int16_t int16_t; 94 | 95 | enum { echo_hist_size = 8 }; 96 | 97 | enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; 98 | enum { brr_buf_size = 12 }; 99 | struct voice_t 100 | { 101 | int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) 102 | int* buf_pos; // place in buffer where next samples will be decoded 103 | int interp_pos; // relative fractional position in sample (0x1000 = 1.0) 104 | int brr_addr; // address of current BRR block 105 | int brr_offset; // current decoding offset in BRR block 106 | int kon_delay; // KON delay/current setup phase 107 | env_mode_t env_mode; 108 | int env; // current envelope level 109 | int hidden_env; // used by GAIN mode 7, very obscure quirk 110 | int volume [2]; // copy of volume from DSP registers, with surround disabled 111 | int enabled; // -1 if enabled, 0 if muted 112 | }; 113 | private: 114 | struct state_t 115 | { 116 | uint8_t regs [register_count]; 117 | 118 | // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) 119 | int echo_hist [echo_hist_size * 2] [2]; 120 | int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] 121 | 122 | int every_other_sample; // toggles every sample 123 | int kon; // KON value when last checked 124 | int noise; 125 | int echo_offset; // offset from ESA in echo buffer 126 | int echo_length; // number of bytes that echo_offset will stop at 127 | int phase; // next clock cycle to run (0-31) 128 | unsigned counters [4]; 129 | 130 | int new_kon; 131 | int t_koff; 132 | 133 | voice_t voices [voice_count]; 134 | 135 | unsigned* counter_select [32]; 136 | 137 | // non-emulation state 138 | uint8_t* ram; // 64K shared RAM between DSP and SMP 139 | int mute_mask; 140 | int surround_threshold; 141 | sample_t* out; 142 | sample_t* out_end; 143 | sample_t* out_begin; 144 | sample_t extra [extra_size]; 145 | }; 146 | state_t m; 147 | 148 | void init_counter(); 149 | void run_counter( int ); 150 | void soft_reset_common(); 151 | void write_outline( int addr, int data ); 152 | void update_voice_vol( int addr ); 153 | }; 154 | 155 | #include 156 | 157 | inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } 158 | 159 | inline int SPC_DSP::read( int addr ) const 160 | { 161 | assert( (unsigned) addr < register_count ); 162 | return m.regs [addr]; 163 | } 164 | 165 | inline void SPC_DSP::update_voice_vol( int addr ) 166 | { 167 | int l = (int8_t) m.regs [addr + v_voll]; 168 | int r = (int8_t) m.regs [addr + v_volr]; 169 | 170 | if ( l * r < m.surround_threshold ) 171 | { 172 | // signs differ, so negate those that are negative 173 | l ^= l >> 7; 174 | r ^= r >> 7; 175 | } 176 | 177 | voice_t& v = m.voices [addr >> 4]; 178 | int enabled = v.enabled; 179 | v.volume [0] = l & enabled; 180 | v.volume [1] = r & enabled; 181 | } 182 | 183 | inline void SPC_DSP::write( int addr, int data ) 184 | { 185 | assert( (unsigned) addr < register_count ); 186 | 187 | m.regs [addr] = (uint8_t) data; 188 | int low = addr & 0x0F; 189 | if ( low < 0x2 ) // voice volumes 190 | { 191 | update_voice_vol( low ^ addr ); 192 | } 193 | else if ( low == 0xC ) 194 | { 195 | if ( addr == r_kon ) 196 | m.new_kon = (uint8_t) data; 197 | 198 | if ( addr == r_endx ) // always cleared, regardless of data written 199 | m.regs [r_endx] = 0; 200 | } 201 | } 202 | 203 | inline void SPC_DSP::disable_surround( bool disable ) 204 | { 205 | m.surround_threshold = disable ? 0 : -0x4000; 206 | } 207 | 208 | #define SPC_NO_COPY_STATE_FUNCS 1 209 | 210 | #define SPC_LESS_ACCURATE 1 211 | 212 | #endif 213 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/SPC_Filter.cpp: -------------------------------------------------------------------------------- 1 | // snes_spc 0.9.0. http://www.slack.net/~ant/ 2 | 3 | #include "SPC_Filter.h" 4 | 5 | #include 6 | 7 | /* Copyright (C) 2007 Shay Green. This module is free software; you 8 | can redistribute it and/or modify it under the terms of the GNU Lesser 9 | General Public License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. This 11 | module is distributed in the hope that it will be useful, but WITHOUT ANY 12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 14 | details. You should have received a copy of the GNU Lesser General Public 15 | License along with this module; if not, write to the Free Software Foundation, 16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 17 | 18 | #include "blargg_source.h" 19 | 20 | void SPC_Filter::clear() { memset( ch, 0, sizeof ch ); } 21 | 22 | SPC_Filter::SPC_Filter() 23 | { 24 | gain = gain_unit; 25 | bass = bass_norm; 26 | clear(); 27 | } 28 | 29 | void SPC_Filter::run( short* io, int count ) 30 | { 31 | require( (count & 1) == 0 ); // must be even 32 | 33 | int const gain = this->gain; 34 | int const bass = this->bass; 35 | chan_t* c = &ch [2]; 36 | do 37 | { 38 | // cache in registers 39 | int sum = (--c)->sum; 40 | int pp1 = c->pp1; 41 | int p1 = c->p1; 42 | 43 | for ( int i = 0; i < count; i += 2 ) 44 | { 45 | // Low-pass filter (two point FIR with coeffs 0.25, 0.75) 46 | int f = io [i] + p1; 47 | p1 = io [i] * 3; 48 | 49 | // High-pass filter ("leaky integrator") 50 | int delta = f - pp1; 51 | pp1 = f; 52 | int s = sum >> (gain_bits + 2); 53 | sum += (delta * gain) - (sum >> bass); 54 | 55 | // Clamp to 16 bits 56 | if ( (short) s != s ) 57 | s = (s >> 31) ^ 0x7FFF; 58 | 59 | io [i] = (short) s; 60 | } 61 | 62 | c->p1 = p1; 63 | c->pp1 = pp1; 64 | c->sum = sum; 65 | ++io; 66 | } 67 | while ( c != ch ); 68 | } 69 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/SPC_Filter.h: -------------------------------------------------------------------------------- 1 | // Simple low-pass and high-pass filter to better match sound output of a SNES 2 | 3 | // snes_spc 0.9.0 4 | #ifndef SPC_FILTER_H 5 | #define SPC_FILTER_H 6 | 7 | #include "blargg_common.h" 8 | 9 | struct SPC_Filter { 10 | public: 11 | 12 | // Filters count samples of stereo sound in place. Count must be a multiple of 2. 13 | typedef short sample_t; 14 | void run( sample_t* io, int count ); 15 | 16 | // Optional features 17 | 18 | // Clears filter to silence 19 | void clear(); 20 | 21 | // Sets gain (volume), where gain_unit is normal. Gains greater than gain_unit 22 | // are fine, since output is clamped to 16-bit sample range. 23 | enum { gain_unit = 0x100 }; 24 | void set_gain( int gain ); 25 | 26 | // Sets amount of bass (logarithmic scale) 27 | enum { bass_none = 0 }; 28 | enum { bass_norm = 8 }; // normal amount 29 | enum { bass_max = 31 }; 30 | void set_bass( int bass ); 31 | 32 | public: 33 | SPC_Filter(); 34 | BLARGG_DISABLE_NOTHROW 35 | private: 36 | enum { gain_bits = 8 }; 37 | int gain; 38 | int bass; 39 | struct chan_t { int p1, pp1, sum; }; 40 | chan_t ch [2]; 41 | }; 42 | 43 | inline void SPC_Filter::set_gain( int g ) { gain = g; } 44 | 45 | inline void SPC_Filter::set_bass( int b ) { bass = b; } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/blargg_common.h: -------------------------------------------------------------------------------- 1 | // Sets up common environment for Shay Green's libraries. 2 | // To change configuration options, modify blargg_config.h, not this file. 3 | 4 | // snes_spc 0.9.0 5 | #ifndef BLARGG_COMMON_H 6 | #define BLARGG_COMMON_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #undef BLARGG_COMMON_H 14 | // allow blargg_config.h to #include blargg_common.h 15 | #include "blargg_config.h" 16 | #ifndef BLARGG_COMMON_H 17 | #define BLARGG_COMMON_H 18 | 19 | // BLARGG_RESTRICT: equivalent to restrict, where supported 20 | #if defined (__GNUC__) || _MSC_VER >= 1100 21 | #define BLARGG_RESTRICT __restrict 22 | #else 23 | #define BLARGG_RESTRICT 24 | #endif 25 | 26 | // STATIC_CAST(T,expr): Used in place of static_cast (expr) 27 | #ifndef STATIC_CAST 28 | #define STATIC_CAST(T,expr) ((T) (expr)) 29 | #endif 30 | 31 | // blargg_err_t (0 on success, otherwise error string) 32 | #ifndef blargg_err_t 33 | typedef const char* blargg_err_t; 34 | #endif 35 | 36 | // blargg_vector - very lightweight vector of POD types (no constructor/destructor) 37 | template 38 | class blargg_vector { 39 | T* begin_; 40 | size_t size_; 41 | public: 42 | blargg_vector() : begin_( 0 ), size_( 0 ) { } 43 | ~blargg_vector() { free( begin_ ); } 44 | size_t size() const { return size_; } 45 | T* begin() const { return begin_; } 46 | T* end() const { return begin_ + size_; } 47 | blargg_err_t resize( size_t n ) 48 | { 49 | // TODO: blargg_common.cpp to hold this as an outline function, ugh 50 | void* p = realloc( begin_, n * sizeof (T) ); 51 | if ( p ) 52 | begin_ = (T*) p; 53 | else if ( n > size_ ) // realloc failure only a problem if expanding 54 | return "Out of memory"; 55 | size_ = n; 56 | return 0; 57 | } 58 | void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } 59 | T& operator [] ( size_t n ) const 60 | { 61 | assert( n <= size_ ); // <= to allow past-the-end value 62 | return begin_ [n]; 63 | } 64 | }; 65 | 66 | #ifndef BLARGG_DISABLE_NOTHROW 67 | // throw spec mandatory in ISO C++ if operator new can return NULL 68 | #if __cplusplus >= 199711 || defined (__GNUC__) 69 | #define BLARGG_THROWS( spec ) throw spec 70 | #else 71 | #define BLARGG_THROWS( spec ) 72 | #endif 73 | #define BLARGG_DISABLE_NOTHROW \ 74 | void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ 75 | void operator delete ( void* p ) { free( p ); } 76 | #define BLARGG_NEW new 77 | #else 78 | #include 79 | #define BLARGG_NEW new (std::nothrow) 80 | #endif 81 | 82 | // BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) 83 | #define BLARGG_4CHAR( a, b, c, d ) \ 84 | ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) 85 | 86 | // BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. 87 | #ifndef BOOST_STATIC_ASSERT 88 | #ifdef _MSC_VER 89 | // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified 90 | #define BOOST_STATIC_ASSERT( expr ) \ 91 | void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) 92 | #else 93 | // Some other compilers fail when declaring same function multiple times in class, 94 | // so differentiate them by line 95 | #define BOOST_STATIC_ASSERT( expr ) \ 96 | void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) 97 | #endif 98 | #endif 99 | 100 | // BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, 101 | // compiler is assumed to support bool. If undefined, availability is determined. 102 | #ifndef BLARGG_COMPILER_HAS_BOOL 103 | #if defined (__MWERKS__) 104 | #if !__option(bool) 105 | #define BLARGG_COMPILER_HAS_BOOL 0 106 | #endif 107 | #elif defined (_MSC_VER) 108 | #if _MSC_VER < 1100 109 | #define BLARGG_COMPILER_HAS_BOOL 0 110 | #endif 111 | #elif defined (__GNUC__) 112 | // supports bool 113 | #elif __cplusplus < 199711 114 | #define BLARGG_COMPILER_HAS_BOOL 0 115 | #endif 116 | #endif 117 | #if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL 118 | // If you get errors here, modify your blargg_config.h file 119 | typedef int bool; 120 | const bool true = 1; 121 | const bool false = 0; 122 | #endif 123 | 124 | // blargg_long/blargg_ulong = at least 32 bits, int if it's big enough 125 | 126 | #if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF 127 | typedef long blargg_long; 128 | #else 129 | typedef int blargg_long; 130 | #endif 131 | 132 | #if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF 133 | typedef unsigned long blargg_ulong; 134 | #else 135 | typedef unsigned blargg_ulong; 136 | #endif 137 | 138 | // BOOST::int8_t etc. 139 | 140 | // HAVE_STDINT_H: If defined, use for int8_t etc. 141 | #if defined (HAVE_STDINT_H) 142 | #include 143 | #define BOOST 144 | 145 | // HAVE_INTTYPES_H: If defined, use for int8_t etc. 146 | #elif defined (HAVE_INTTYPES_H) 147 | #include 148 | #define BOOST 149 | 150 | #else 151 | struct BOOST 152 | { 153 | #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F 154 | typedef signed char int8_t; 155 | typedef unsigned char uint8_t; 156 | #else 157 | // No suitable 8-bit type available 158 | typedef struct see_blargg_common_h int8_t; 159 | typedef struct see_blargg_common_h uint8_t; 160 | #endif 161 | 162 | #if USHRT_MAX == 0xFFFF 163 | typedef short int16_t; 164 | typedef unsigned short uint16_t; 165 | #else 166 | // No suitable 16-bit type available 167 | typedef struct see_blargg_common_h int16_t; 168 | typedef struct see_blargg_common_h uint16_t; 169 | #endif 170 | 171 | #if ULONG_MAX == 0xFFFFFFFF 172 | typedef long int32_t; 173 | typedef unsigned long uint32_t; 174 | #elif UINT_MAX == 0xFFFFFFFF 175 | typedef int int32_t; 176 | typedef unsigned int uint32_t; 177 | #else 178 | // No suitable 32-bit type available 179 | typedef struct see_blargg_common_h int32_t; 180 | typedef struct see_blargg_common_h uint32_t; 181 | #endif 182 | }; 183 | #endif 184 | 185 | #endif 186 | #endif 187 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/blargg_config.h: -------------------------------------------------------------------------------- 1 | // snes_spc 0.9.0 user configuration file. Don't replace when updating library. 2 | 3 | // snes_spc 0.9.0 4 | #ifndef BLARGG_CONFIG_H 5 | #define BLARGG_CONFIG_H 6 | 7 | // Uncomment to disable debugging checks 8 | //#define NDEBUG 1 9 | 10 | // Uncomment to enable platform-specific (and possibly non-portable) optimizations 11 | //#define BLARGG_NONPORTABLE 1 12 | 13 | // Uncomment if automatic byte-order determination doesn't work 14 | //#define BLARGG_BIG_ENDIAN 1 15 | 16 | // Uncomment if you get errors in the bool section of blargg_common.h 17 | //#define BLARGG_COMPILER_HAS_BOOL 1 18 | 19 | // Use standard config.h if present 20 | #ifdef HAVE_CONFIG_H 21 | #include "config.h" 22 | #endif 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/blargg_endian.h: -------------------------------------------------------------------------------- 1 | // CPU Byte Order Utilities 2 | 3 | // snes_spc 0.9.0 4 | #ifndef BLARGG_ENDIAN 5 | #define BLARGG_ENDIAN 6 | 7 | #include "blargg_common.h" 8 | 9 | // BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) 10 | #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ 11 | defined (__x86_64__) || defined (__ia64__) || defined (__i386__) 12 | #define BLARGG_CPU_X86 1 13 | #define BLARGG_CPU_CISC 1 14 | #endif 15 | 16 | #if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) 17 | #define BLARGG_CPU_POWERPC 1 18 | #define BLARGG_CPU_RISC 1 19 | #endif 20 | 21 | // BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only 22 | // one may be #defined to 1. Only needed if something actually depends on byte order. 23 | #if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) 24 | #ifdef __GLIBC__ 25 | // GCC handles this for us 26 | #include 27 | #if __BYTE_ORDER == __LITTLE_ENDIAN 28 | #define BLARGG_LITTLE_ENDIAN 1 29 | #elif __BYTE_ORDER == __BIG_ENDIAN 30 | #define BLARGG_BIG_ENDIAN 1 31 | #endif 32 | #else 33 | 34 | #if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ 35 | (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) 36 | #define BLARGG_LITTLE_ENDIAN 1 37 | #endif 38 | 39 | #if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ 40 | defined (__sparc__) || BLARGG_CPU_POWERPC || \ 41 | (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) 42 | #define BLARGG_BIG_ENDIAN 1 43 | #elif !defined (__mips__) 44 | // No endian specified; assume little-endian, since it's most common 45 | #define BLARGG_LITTLE_ENDIAN 1 46 | #endif 47 | #endif 48 | #endif 49 | 50 | #if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN 51 | #undef BLARGG_LITTLE_ENDIAN 52 | #undef BLARGG_BIG_ENDIAN 53 | #endif 54 | 55 | inline void blargg_verify_byte_order() 56 | { 57 | #ifndef NDEBUG 58 | #if BLARGG_BIG_ENDIAN 59 | volatile int i = 1; 60 | assert( *(volatile char*) &i == 0 ); 61 | #elif BLARGG_LITTLE_ENDIAN 62 | volatile int i = 1; 63 | assert( *(volatile char*) &i != 0 ); 64 | #endif 65 | #endif 66 | } 67 | 68 | inline unsigned get_le16( void const* p ) 69 | { 70 | return (unsigned) ((unsigned char const*) p) [1] << 8 | 71 | (unsigned) ((unsigned char const*) p) [0]; 72 | } 73 | 74 | inline unsigned get_be16( void const* p ) 75 | { 76 | return (unsigned) ((unsigned char const*) p) [0] << 8 | 77 | (unsigned) ((unsigned char const*) p) [1]; 78 | } 79 | 80 | inline blargg_ulong get_le32( void const* p ) 81 | { 82 | return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | 83 | (blargg_ulong) ((unsigned char const*) p) [2] << 16 | 84 | (blargg_ulong) ((unsigned char const*) p) [1] << 8 | 85 | (blargg_ulong) ((unsigned char const*) p) [0]; 86 | } 87 | 88 | inline blargg_ulong get_be32( void const* p ) 89 | { 90 | return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | 91 | (blargg_ulong) ((unsigned char const*) p) [1] << 16 | 92 | (blargg_ulong) ((unsigned char const*) p) [2] << 8 | 93 | (blargg_ulong) ((unsigned char const*) p) [3]; 94 | } 95 | 96 | inline void set_le16( void* p, unsigned n ) 97 | { 98 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); 99 | ((unsigned char*) p) [0] = (unsigned char) n; 100 | } 101 | 102 | inline void set_be16( void* p, unsigned n ) 103 | { 104 | ((unsigned char*) p) [0] = (unsigned char) (n >> 8); 105 | ((unsigned char*) p) [1] = (unsigned char) n; 106 | } 107 | 108 | inline void set_le32( void* p, blargg_ulong n ) 109 | { 110 | ((unsigned char*) p) [0] = (unsigned char) n; 111 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); 112 | ((unsigned char*) p) [2] = (unsigned char) (n >> 16); 113 | ((unsigned char*) p) [3] = (unsigned char) (n >> 24); 114 | } 115 | 116 | inline void set_be32( void* p, blargg_ulong n ) 117 | { 118 | ((unsigned char*) p) [3] = (unsigned char) n; 119 | ((unsigned char*) p) [2] = (unsigned char) (n >> 8); 120 | ((unsigned char*) p) [1] = (unsigned char) (n >> 16); 121 | ((unsigned char*) p) [0] = (unsigned char) (n >> 24); 122 | } 123 | 124 | #if BLARGG_NONPORTABLE 125 | // Optimized implementation if byte order is known 126 | #if BLARGG_LITTLE_ENDIAN 127 | #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) 128 | #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) 129 | #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) 130 | #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) 131 | #elif BLARGG_BIG_ENDIAN 132 | #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) 133 | #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) 134 | #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) 135 | #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) 136 | 137 | #if BLARGG_CPU_POWERPC 138 | // PowerPC has special byte-reversed instructions 139 | #if defined (__MWERKS__) 140 | #define GET_LE16( addr ) (__lhbrx( addr, 0 )) 141 | #define GET_LE32( addr ) (__lwbrx( addr, 0 )) 142 | #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) 143 | #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) 144 | #elif defined (__GNUC__) 145 | #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) 146 | #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) 147 | #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) 148 | #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) 149 | #endif 150 | #endif 151 | #endif 152 | #endif 153 | 154 | #ifndef GET_LE16 155 | #define GET_LE16( addr ) get_le16( addr ) 156 | #define SET_LE16( addr, data ) set_le16( addr, data ) 157 | #endif 158 | 159 | #ifndef GET_LE32 160 | #define GET_LE32( addr ) get_le32( addr ) 161 | #define SET_LE32( addr, data ) set_le32( addr, data ) 162 | #endif 163 | 164 | #ifndef GET_BE16 165 | #define GET_BE16( addr ) get_be16( addr ) 166 | #define SET_BE16( addr, data ) set_be16( addr, data ) 167 | #endif 168 | 169 | #ifndef GET_BE32 170 | #define GET_BE32( addr ) get_be32( addr ) 171 | #define SET_BE32( addr, data ) set_be32( addr, data ) 172 | #endif 173 | 174 | // auto-selecting versions 175 | 176 | inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } 177 | inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } 178 | inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } 179 | inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } 180 | inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } 181 | inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } 182 | inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } 183 | inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/blargg_source.h: -------------------------------------------------------------------------------- 1 | /* Included at the beginning of library source files, after all other #include lines. 2 | Sets up helpful macros and services used in my source code. They don't need 3 | module an annoying module prefix on their names since they are defined after 4 | all other #include lines. */ 5 | 6 | // snes_spc 0.9.0 7 | #ifndef BLARGG_SOURCE_H 8 | #define BLARGG_SOURCE_H 9 | 10 | // If debugging is enabled, abort program if expr is false. Meant for checking 11 | // internal state and consistency. A failed assertion indicates a bug in the module. 12 | // void assert( bool expr ); 13 | #include 14 | 15 | // If debugging is enabled and expr is false, abort program. Meant for checking 16 | // caller-supplied parameters and operations that are outside the control of the 17 | // module. A failed requirement indicates a bug outside the module. 18 | // void require( bool expr ); 19 | #undef require 20 | #define require( expr ) assert( expr ) 21 | 22 | // Like printf() except output goes to debug log file. Might be defined to do 23 | // nothing (not even evaluate its arguments). 24 | // void dprintf( const char* format, ... ); 25 | static inline void blargg_dprintf_( const char*, ... ) { } 26 | #undef dprintf 27 | #define dprintf (1) ? (void) 0 : blargg_dprintf_ 28 | 29 | // If enabled, evaluate expr and if false, make debug log entry with source file 30 | // and line. Meant for finding situations that should be examined further, but that 31 | // don't indicate a problem. In all cases, execution continues normally. 32 | #undef check 33 | #define check( expr ) ((void) 0) 34 | 35 | // If expr yields error string, return it from current function, otherwise continue. 36 | #undef RETURN_ERR 37 | #define RETURN_ERR( expr ) do { \ 38 | blargg_err_t blargg_return_err_ = (expr); \ 39 | if ( blargg_return_err_ ) return blargg_return_err_; \ 40 | } while ( 0 ) 41 | 42 | // If ptr is 0, return out of memory error string. 43 | #undef CHECK_ALLOC 44 | #define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) 45 | 46 | // Avoid any macros which evaluate their arguments multiple times 47 | #undef min 48 | #undef max 49 | 50 | #define DEF_MIN_MAX( type ) \ 51 | static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\ 52 | static inline type max( type x, type y ) { if ( y < x ) return x; return y; } 53 | 54 | DEF_MIN_MAX( int ) 55 | DEF_MIN_MAX( unsigned ) 56 | DEF_MIN_MAX( long ) 57 | DEF_MIN_MAX( unsigned long ) 58 | DEF_MIN_MAX( float ) 59 | DEF_MIN_MAX( double ) 60 | 61 | #undef DEF_MIN_MAX 62 | 63 | /* 64 | // using const references generates crappy code, and I am currenly only using these 65 | // for built-in types, so they take arguments by value 66 | 67 | // TODO: remove 68 | inline int min( int x, int y ) 69 | template 70 | inline T min( T x, T y ) 71 | { 72 | if ( x < y ) 73 | return x; 74 | return y; 75 | } 76 | 77 | template 78 | inline T max( T x, T y ) 79 | { 80 | if ( x < y ) 81 | return y; 82 | return x; 83 | } 84 | */ 85 | 86 | // TODO: good idea? bad idea? 87 | #undef byte 88 | #define byte byte_ 89 | typedef unsigned char byte; 90 | 91 | // deprecated 92 | #define BLARGG_CHECK_ALLOC CHECK_ALLOC 93 | #define BLARGG_RETURN_ERR RETURN_ERR 94 | 95 | // BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check 96 | #ifdef BLARGG_SOURCE_BEGIN 97 | #include BLARGG_SOURCE_BEGIN 98 | #endif 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/dsp.cpp: -------------------------------------------------------------------------------- 1 | // snes_spc 0.9.0. http://www.slack.net/~ant/ 2 | 3 | #include "dsp.h" 4 | 5 | #include "SPC_DSP.h" 6 | 7 | /* Copyright (C) 2007 Shay Green. This module is free software; you 8 | can redistribute it and/or modify it under the terms of the GNU Lesser 9 | General Public License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. This 11 | module is distributed in the hope that it will be useful, but WITHOUT ANY 12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 14 | details. You should have received a copy of the GNU Lesser General Public 15 | License along with this module; if not, write to the Free Software Foundation, 16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 17 | 18 | #include "blargg_source.h" 19 | 20 | SPC_DSP* spc_dsp_new( void ) 21 | { 22 | // be sure constants match 23 | assert( spc_dsp_voice_count == (int) SPC_DSP::voice_count ); 24 | assert( spc_dsp_register_count == (int) SPC_DSP::register_count ); 25 | #if !SPC_NO_COPY_STATE_FUNCS 26 | assert( spc_dsp_state_size == (int) SPC_DSP::state_size ); 27 | #endif 28 | 29 | return new SPC_DSP; 30 | } 31 | 32 | void spc_dsp_delete ( SPC_DSP* s ) { delete s; } 33 | void spc_dsp_init ( SPC_DSP* s, void* ram_64k ) { s->init( ram_64k ); } 34 | void spc_dsp_set_output ( SPC_DSP* s, spc_dsp_sample_t* p, int n ) { s->set_output( p, n ); } 35 | int spc_dsp_sample_count( SPC_DSP const* s ) { return s->sample_count(); } 36 | void spc_dsp_reset ( SPC_DSP* s ) { s->reset(); } 37 | void spc_dsp_soft_reset ( SPC_DSP* s ) { s->soft_reset(); } 38 | int spc_dsp_read ( SPC_DSP const* s, int addr ) { return s->read( addr ); } 39 | void spc_dsp_write ( SPC_DSP* s, int addr, int data ) { s->write( addr, data ); } 40 | void spc_dsp_run ( SPC_DSP* s, int clock_count ) { s->run( clock_count ); } 41 | void spc_dsp_mute_voices ( SPC_DSP* s, int mask ) { s->mute_voices( mask ); } 42 | void spc_dsp_disable_surround( SPC_DSP* s, int disable ) { s->disable_surround( disable ); } 43 | void spc_dsp_load ( SPC_DSP* s, unsigned char const regs [spc_dsp_register_count] ) { s->load( regs ); } 44 | 45 | #if !SPC_NO_COPY_STATE_FUNCS 46 | void spc_dsp_copy_state ( SPC_DSP* s, unsigned char** p, spc_dsp_copy_func_t f ) { s->copy_state( p, f ); } 47 | int spc_dsp_check_kon ( SPC_DSP* s ) { return s->check_kon(); } 48 | #endif 49 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/dsp.h: -------------------------------------------------------------------------------- 1 | /* SNES SPC-700 DSP emulator C interface (also usable from C++) */ 2 | 3 | /* snes_spc 0.9.0 */ 4 | #ifndef DSP_H 5 | #define DSP_H 6 | 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | typedef struct SPC_DSP SPC_DSP; 14 | 15 | /* Creates new DSP emulator. NULL if out of memory. */ 16 | SPC_DSP* spc_dsp_new( void ); 17 | 18 | /* Frees DSP emulator */ 19 | void spc_dsp_delete( SPC_DSP* ); 20 | 21 | /* Initializes DSP and has it use the 64K RAM provided */ 22 | void spc_dsp_init( SPC_DSP*, void* ram_64k ); 23 | 24 | /* Sets destination for output samples. If out is NULL or out_size is 0, 25 | doesn't generate any. */ 26 | typedef short spc_dsp_sample_t; 27 | void spc_dsp_set_output( SPC_DSP*, spc_dsp_sample_t* out, int out_size ); 28 | 29 | /* Number of samples written to output since it was last set, always 30 | a multiple of 2. Undefined if more samples were generated than 31 | output buffer could hold. */ 32 | int spc_dsp_sample_count( SPC_DSP const* ); 33 | 34 | 35 | /**** Emulation *****/ 36 | 37 | /* Resets DSP to power-on state */ 38 | void spc_dsp_reset( SPC_DSP* ); 39 | 40 | /* Emulates pressing reset switch on SNES */ 41 | void spc_dsp_soft_reset( SPC_DSP* ); 42 | 43 | /* Reads/writes DSP registers. For accuracy, you must first call spc_dsp_run() */ 44 | /* to catch the DSP up to present. */ 45 | int spc_dsp_read ( SPC_DSP const*, int addr ); 46 | void spc_dsp_write( SPC_DSP*, int addr, int data ); 47 | 48 | /* Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks */ 49 | /* a pair of samples is be generated. */ 50 | void spc_dsp_run( SPC_DSP*, int clock_count ); 51 | 52 | 53 | /**** Sound control *****/ 54 | 55 | /* Mutes voices corresponding to non-zero bits in mask. Reduces emulation accuracy. */ 56 | enum { spc_dsp_voice_count = 8 }; 57 | void spc_dsp_mute_voices( SPC_DSP*, int mask ); 58 | 59 | /* If true, prevents channels and global volumes from being phase-negated. 60 | Only supported by fast DSP; has no effect on accurate DSP. */ 61 | void spc_dsp_disable_surround( SPC_DSP*, int disable ); 62 | 63 | 64 | /**** State save/load *****/ 65 | 66 | /* Resets DSP and uses supplied values to initialize registers */ 67 | enum { spc_dsp_register_count = 128 }; 68 | void spc_dsp_load( SPC_DSP*, unsigned char const regs [spc_dsp_register_count] ); 69 | 70 | /* Saves/loads exact emulator state (accurate DSP only) */ 71 | enum { spc_dsp_state_size = 640 }; /* maximum space needed when saving */ 72 | typedef void (*spc_dsp_copy_func_t)( unsigned char** io, void* state, size_t ); 73 | void spc_dsp_copy_state( SPC_DSP*, unsigned char** io, spc_dsp_copy_func_t ); 74 | 75 | /* Returns non-zero if new key-on events occurred since last call (accurate DSP only) */ 76 | int spc_dsp_check_kon( SPC_DSP* ); 77 | 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/spc.cpp: -------------------------------------------------------------------------------- 1 | // snes_spc 0.9.0. http://www.slack.net/~ant/ 2 | 3 | #define EMSCRIPTEN_KEEPALIVE __attribute__((used)) 4 | #include "spc.h" 5 | 6 | #include "SNES_SPC.h" 7 | #include "SPC_Filter.h" 8 | 9 | /* Copyright (C) 2004-2007 Shay Green. This module is free software; you 10 | can redistribute it and/or modify it under the terms of the GNU Lesser 11 | General Public License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. This 13 | module is distributed in the hope that it will be useful, but WITHOUT ANY 14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 16 | details. You should have received a copy of the GNU Lesser General Public 17 | License along with this module; if not, write to the Free Software Foundation, 18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 19 | 20 | #include "blargg_source.h" 21 | 22 | SNES_SPC* EMSCRIPTEN_KEEPALIVE spc_new( void ) 23 | { 24 | // be sure constants match 25 | assert( spc_sample_rate == (int) SNES_SPC::sample_rate ); 26 | assert( spc_rom_size == (int) SNES_SPC::rom_size ); 27 | assert( spc_clock_rate == (int) SNES_SPC::clock_rate ); 28 | assert( spc_clocks_per_sample == (int) SNES_SPC::clocks_per_sample ); 29 | assert( spc_port_count == (int) SNES_SPC::port_count ); 30 | assert( spc_voice_count == (int) SNES_SPC::voice_count ); 31 | assert( spc_tempo_unit == (int) SNES_SPC::tempo_unit ); 32 | assert( spc_file_size == (int) SNES_SPC::spc_file_size ); 33 | #if !SPC_NO_COPY_STATE_FUNCS 34 | assert( spc_state_size == (int) SNES_SPC::state_size ); 35 | #endif 36 | 37 | SNES_SPC* s = new SNES_SPC; 38 | if ( s && s->init() ) 39 | { 40 | delete s; 41 | s = 0; 42 | } 43 | return s; 44 | } 45 | 46 | void spc_delete ( SNES_SPC* s ) { delete s; } 47 | void spc_init_rom ( SNES_SPC* s, unsigned char const r [64] ) { s->init_rom( r ); } 48 | void EMSCRIPTEN_KEEPALIVE spc_set_output ( SNES_SPC* s, spc_sample_t* p, int n ) { s->set_output( p, n ); } 49 | int spc_sample_count ( SNES_SPC const* s ) { return s->sample_count(); } 50 | void spc_reset ( SNES_SPC* s ) { s->reset(); } 51 | void spc_soft_reset ( SNES_SPC* s ) { s->soft_reset(); } 52 | int spc_read_port ( SNES_SPC* s, spc_time_t t, int p ) { return s->read_port( t, p ); } 53 | void spc_write_port ( SNES_SPC* s, spc_time_t t, int p, int d ) { s->write_port( t, p, d ); } 54 | void spc_end_frame ( SNES_SPC* s, spc_time_t t ) { s->end_frame( t ); } 55 | void spc_mute_voices ( SNES_SPC* s, int mask ) { s->mute_voices( mask ); } 56 | void spc_disable_surround( SNES_SPC* s, int disable ) { s->disable_surround( disable ); } 57 | void EMSCRIPTEN_KEEPALIVE spc_set_tempo ( SNES_SPC* s, int tempo ) { s->set_tempo( tempo ); } 58 | spc_err_t EMSCRIPTEN_KEEPALIVE spc_load_spc ( SNES_SPC* s, void const* p, long n ) { return s->load_spc( p, n ); } 59 | void EMSCRIPTEN_KEEPALIVE spc_clear_echo ( SNES_SPC* s ) { s->clear_echo(); } 60 | spc_err_t EMSCRIPTEN_KEEPALIVE spc_play ( SNES_SPC* s, int count, short* out ) { return s->play( count, out ); } 61 | spc_err_t spc_skip ( SNES_SPC* s, int count ) { return s->skip( count ); } 62 | #if !SPC_NO_COPY_STATE_FUNCS 63 | void spc_copy_state ( SNES_SPC* s, unsigned char** p, spc_copy_func_t f ) { s->copy_state( p, f ); } 64 | void spc_init_header ( void* spc_out ) { SNES_SPC::init_header( spc_out ); } 65 | void spc_save_spc ( SNES_SPC* s, void* spc_out ) { s->save_spc( spc_out ); } 66 | int spc_check_kon ( SNES_SPC* s ) { return s->check_kon(); } 67 | #endif 68 | 69 | SPC_Filter* EMSCRIPTEN_KEEPALIVE spc_filter_new( void ) { return new SPC_Filter; } 70 | void spc_filter_delete( SPC_Filter* f ) { delete f; } 71 | void EMSCRIPTEN_KEEPALIVE spc_filter_run( SPC_Filter* f, spc_sample_t* p, int s ) { f->run( p, s ); } 72 | void EMSCRIPTEN_KEEPALIVE spc_filter_clear( SPC_Filter* f ) { f->clear(); } 73 | void spc_filter_set_gain( SPC_Filter* f, int gain ) { f->set_gain( gain ); } 74 | void spc_filter_set_bass( SPC_Filter* f, int bass ) { f->set_bass( bass ); } 75 | -------------------------------------------------------------------------------- /snes_spc-0.9.0/snes_spc/spc.h: -------------------------------------------------------------------------------- 1 | /* SNES SPC-700 APU emulator C interface (also usable from C++) */ 2 | 3 | /* snes_spc 0.9.0 */ 4 | #ifndef SPC_H 5 | #define SPC_H 6 | 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /* Error string return. NULL if success, otherwise error message. */ 14 | typedef const char* spc_err_t; 15 | 16 | typedef struct SNES_SPC SNES_SPC; 17 | 18 | /* Creates new SPC emulator. NULL if out of memory. */ 19 | SNES_SPC* spc_new( void ); 20 | 21 | /* Frees SPC emulator */ 22 | void spc_delete( SNES_SPC* ); 23 | 24 | /* Sample pairs generated per second */ 25 | enum { spc_sample_rate = 32000 }; 26 | 27 | 28 | /**** Emulator use ****/ 29 | 30 | /* Sets IPL ROM data. Library does not include ROM data. Most SPC music files 31 | don't need ROM, but a full emulator must provide this. */ 32 | enum { spc_rom_size = 0x40 }; 33 | void spc_init_rom( SNES_SPC*, unsigned char const rom [spc_rom_size] ); 34 | 35 | /* Sets destination for output samples */ 36 | typedef short spc_sample_t; 37 | void spc_set_output( SNES_SPC*, spc_sample_t* out, int out_size ); 38 | 39 | /* Number of samples written to output since last set */ 40 | int spc_sample_count( SNES_SPC const* ); 41 | 42 | /* Resets SPC to power-on state. This resets your output buffer, so you must 43 | call spc_set_output() after this. */ 44 | void spc_reset( SNES_SPC* ); 45 | 46 | /* Emulates pressing reset switch on SNES. This resets your output buffer, so 47 | you must call spc_set_output() after this. */ 48 | void spc_soft_reset( SNES_SPC* ); 49 | 50 | /* 1024000 SPC clocks per second, sample pair every 32 clocks */ 51 | typedef int spc_time_t; 52 | enum { spc_clock_rate = 1024000 }; 53 | enum { spc_clocks_per_sample = 32 }; 54 | 55 | /* Reads/writes port at specified time */ 56 | enum { spc_port_count = 4 }; 57 | int spc_read_port ( SNES_SPC*, spc_time_t, int port ); 58 | void spc_write_port( SNES_SPC*, spc_time_t, int port, int data ); 59 | 60 | /* Runs SPC to end_time and starts a new time frame at 0 */ 61 | void spc_end_frame( SNES_SPC*, spc_time_t end_time ); 62 | 63 | 64 | /**** Sound control ****/ 65 | 66 | /*Mutes voices corresponding to non-zero bits in mask. Reduces emulation accuracy. */ 67 | enum { spc_voice_count = 8 }; 68 | void spc_mute_voices( SNES_SPC*, int mask ); 69 | 70 | /* If true, prevents channels and global volumes from being phase-negated. 71 | Only supported by fast DSP; has no effect on accurate DSP. */ 72 | void spc_disable_surround( SNES_SPC*, int disable ); 73 | 74 | /* Sets tempo, where spc_tempo_unit = normal, spc_tempo_unit / 2 = half speed, etc. */ 75 | enum { spc_tempo_unit = 0x100 }; 76 | void spc_set_tempo( SNES_SPC*, int ); 77 | 78 | 79 | /**** SPC music playback *****/ 80 | 81 | /* Loads SPC data into emulator. Returns NULL on success, otherwise error string. */ 82 | spc_err_t spc_load_spc( SNES_SPC*, void const* spc_in, long size ); 83 | 84 | /* Clears echo region. Useful after loading an SPC as many have garbage in echo. */ 85 | void spc_clear_echo( SNES_SPC* ); 86 | 87 | /* Plays for count samples and write samples to out. Discards samples if out 88 | is NULL. Count must be a multiple of 2 since output is stereo. */ 89 | spc_err_t spc_play( SNES_SPC*, int count, short* out ); 90 | 91 | /* Skips count samples. Several times faster than spc_play(). */ 92 | spc_err_t spc_skip( SNES_SPC*, int count ); 93 | 94 | 95 | /**** State save/load (only available with accurate DSP) ****/ 96 | 97 | /* Saves/loads exact emulator state */ 98 | enum { spc_state_size = 67 * 1024L }; /* maximum space needed when saving */ 99 | typedef void (*spc_copy_func_t)( unsigned char** io, void* state, size_t ); 100 | void spc_copy_state( SNES_SPC*, unsigned char** io, spc_copy_func_t ); 101 | 102 | /* Writes minimal SPC file header to spc_out */ 103 | void spc_init_header( void* spc_out ); 104 | 105 | /* Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. 106 | Does not set up SPC header; use spc_init_header() for that. */ 107 | enum { spc_file_size = 0x10200 }; /* spc_out must have this many bytes allocated */ 108 | void spc_save_spc( SNES_SPC*, void* spc_out ); 109 | 110 | /* Returns non-zero if new key-on events occurred since last check. Useful for 111 | trimming silence while saving an SPC. */ 112 | int spc_check_kon( SNES_SPC* ); 113 | 114 | 115 | /**** SPC_Filter ****/ 116 | 117 | typedef struct SPC_Filter SPC_Filter; 118 | 119 | /* Creates new filter. NULL if out of memory. */ 120 | SPC_Filter* spc_filter_new( void ); 121 | 122 | /* Frees filter */ 123 | void spc_filter_delete( SPC_Filter* ); 124 | 125 | /* Filters count samples of stereo sound in place. Count must be a multiple of 2. */ 126 | void spc_filter_run( SPC_Filter*, spc_sample_t* io, int count ); 127 | 128 | /* Clears filter to silence */ 129 | void spc_filter_clear( SPC_Filter* ); 130 | 131 | /* Sets gain (volume), where spc_filter_gain_unit is normal. Gains greater than 132 | spc_filter_gain_unit are fine, since output is clamped to 16-bit sample range. */ 133 | enum { spc_filter_gain_unit = 0x100 }; 134 | void spc_filter_set_gain( SPC_Filter*, int gain ); 135 | 136 | /* Sets amount of bass (logarithmic scale) */ 137 | enum { spc_filter_bass_none = 0 }; 138 | enum { spc_filter_bass_norm = 8 }; /* normal amount */ 139 | enum { spc_filter_bass_max = 31 }; 140 | void spc_filter_set_bass( SPC_Filter*, int bass ); 141 | 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /songs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/.DS_Store -------------------------------------------------------------------------------- /songs/Super Mario World/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/.DS_Store -------------------------------------------------------------------------------- /songs/Super Mario World/smw-01.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-01.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-02.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-02.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-03.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-03.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-04.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-04.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-05.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-05.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-06.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-06.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-07.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-07.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-08.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-08.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-09.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-09.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-10a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-10a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-10b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-10b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-11a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-11a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-11b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-11b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-11c.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-11c.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-11d.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-11d.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-12a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-12a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-12b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-12b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-12c.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-12c.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-12d.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-12d.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-13a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-13a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-13b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-13b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-13c.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-13c.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-13d.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-13d.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-14a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-14a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-14b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-14b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-14c.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-14c.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-14d.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-14d.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-15a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-15a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-15b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-15b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-16a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-16a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-16b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-16b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-17a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-17a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-17b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-17b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-17c.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-17c.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-17d.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-17d.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-18a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-18a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-18b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-18b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-18c.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-18c.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-18d.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-18d.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-19a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-19a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-19b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-19b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-20.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-20.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-21a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-21a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-21b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-21b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-22.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-22.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-23.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-23.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-24.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-24.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-25.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-25.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-26.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-26.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-27.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-27.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-28.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-28.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-29.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-29.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-30a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-30a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-30b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-30b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-30c.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-30c.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-30d.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-30d.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-31a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-31a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-31b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-31b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-32.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-32.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-33.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-33.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-34.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-34.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-35.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-35.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-36.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-36.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-37a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-37a.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-37b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-37b.spc -------------------------------------------------------------------------------- /songs/Super Mario World/smw-s01.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Super Mario World/smw-s01.spc -------------------------------------------------------------------------------- /songs/Zelda/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/.DS_Store -------------------------------------------------------------------------------- /songs/Zelda/loz3-01.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-01.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-02.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-02.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-03.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-03.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-04a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-04a.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-04b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-04b.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-05a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-05a.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-05b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-05b.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-06.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-06.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-07.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-07.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-08.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-08.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-09.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-09.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-10.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-10.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-11.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-11.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-12.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-12.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-13.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-13.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-14.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-14.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-15.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-15.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-16.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-16.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-17a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-17a.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-17b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-17b.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-18.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-18.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-19.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-19.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-20.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-20.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-21.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-21.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-22a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-22a.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-22b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-22b.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-23.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-23.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-24.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-24.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-25.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-25.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-26.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-26.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-27.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-27.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-28.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-28.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-29.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-29.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-30.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-30.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-31.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-31.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-b01.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-b01.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-b02.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-b02.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-b03.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-b03.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s01.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s01.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s02.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s02.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s03.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s03.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s04.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s04.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s05.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s05.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s06.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s06.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s07.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s07.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s08a.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s08a.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s08b.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s08b.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s09.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s09.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s10.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s10.spc -------------------------------------------------------------------------------- /songs/Zelda/loz3-s11.spc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrRio/js-snes-player/9aa14e281218cbcd57b59375babb5fb33d461c69/songs/Zelda/loz3-s11.spc -------------------------------------------------------------------------------- /songs/index.json: -------------------------------------------------------------------------------- 1 | ["Super Mario World\/smw-01.spc","Super Mario World\/smw-02.spc","Super Mario World\/smw-03.spc","Super Mario World\/smw-04.spc","Super Mario World\/smw-05.spc","Super Mario World\/smw-06.spc","Super Mario World\/smw-07.spc","Super Mario World\/smw-08.spc","Super Mario World\/smw-09.spc","Super Mario World\/smw-10a.spc","Super Mario World\/smw-10b.spc","Super Mario World\/smw-11a.spc","Super Mario World\/smw-11b.spc","Super Mario World\/smw-11c.spc","Super Mario World\/smw-11d.spc","Super Mario World\/smw-12a.spc","Super Mario World\/smw-12b.spc","Super Mario World\/smw-12c.spc","Super Mario World\/smw-12d.spc","Super Mario World\/smw-13a.spc","Super Mario World\/smw-13b.spc","Super Mario World\/smw-13c.spc","Super Mario World\/smw-13d.spc","Super Mario World\/smw-14a.spc","Super Mario World\/smw-14b.spc","Super Mario World\/smw-14c.spc","Super Mario World\/smw-14d.spc","Super Mario World\/smw-15a.spc","Super Mario World\/smw-15b.spc","Super Mario World\/smw-16a.spc","Super Mario World\/smw-16b.spc","Super Mario World\/smw-17a.spc","Super Mario World\/smw-17b.spc","Super Mario World\/smw-17c.spc","Super Mario World\/smw-17d.spc","Super Mario World\/smw-18a.spc","Super Mario World\/smw-18b.spc","Super Mario World\/smw-18c.spc","Super Mario World\/smw-18d.spc","Super Mario World\/smw-19a.spc","Super Mario World\/smw-19b.spc","Super Mario World\/smw-20.spc","Super Mario World\/smw-21a.spc","Super Mario World\/smw-21b.spc","Super Mario World\/smw-22.spc","Super Mario World\/smw-23.spc","Super Mario World\/smw-24.spc","Super Mario World\/smw-25.spc","Super Mario World\/smw-26.spc","Super Mario World\/smw-27.spc","Super Mario World\/smw-28.spc","Super Mario World\/smw-29.spc","Super Mario World\/smw-30a.spc","Super Mario World\/smw-30b.spc","Super Mario World\/smw-30c.spc","Super Mario World\/smw-30d.spc","Super Mario World\/smw-31a.spc","Super Mario World\/smw-31b.spc","Super Mario World\/smw-32.spc","Super Mario World\/smw-33.spc","Super Mario World\/smw-34.spc","Super Mario World\/smw-35.spc","Super Mario World\/smw-36.spc","Super Mario World\/smw-37a.spc","Super Mario World\/smw-37b.spc","Super Mario World\/smw-s01.spc","Zelda\/loz3-01.spc","Zelda\/loz3-02.spc","Zelda\/loz3-03.spc","Zelda\/loz3-04a.spc","Zelda\/loz3-04b.spc","Zelda\/loz3-05a.spc","Zelda\/loz3-05b.spc","Zelda\/loz3-06.spc","Zelda\/loz3-07.spc","Zelda\/loz3-08.spc","Zelda\/loz3-09.spc","Zelda\/loz3-10.spc","Zelda\/loz3-11.spc","Zelda\/loz3-12.spc","Zelda\/loz3-13.spc","Zelda\/loz3-14.spc","Zelda\/loz3-15.spc","Zelda\/loz3-16.spc","Zelda\/loz3-17a.spc","Zelda\/loz3-17b.spc","Zelda\/loz3-18.spc","Zelda\/loz3-19.spc","Zelda\/loz3-20.spc","Zelda\/loz3-21.spc","Zelda\/loz3-22a.spc","Zelda\/loz3-22b.spc","Zelda\/loz3-23.spc","Zelda\/loz3-24.spc","Zelda\/loz3-25.spc","Zelda\/loz3-26.spc","Zelda\/loz3-27.spc","Zelda\/loz3-28.spc","Zelda\/loz3-29.spc","Zelda\/loz3-30.spc","Zelda\/loz3-31.spc","Zelda\/loz3-b01.spc","Zelda\/loz3-b02.spc","Zelda\/loz3-b03.spc","Zelda\/loz3-s01.spc","Zelda\/loz3-s02.spc","Zelda\/loz3-s03.spc","Zelda\/loz3-s04.spc","Zelda\/loz3-s05.spc","Zelda\/loz3-s06.spc","Zelda\/loz3-s07.spc","Zelda\/loz3-s08a.spc","Zelda\/loz3-s08b.spc","Zelda\/loz3-s09.spc","Zelda\/loz3-s10.spc","Zelda\/loz3-s11.spc"] -------------------------------------------------------------------------------- /songs/index.php: -------------------------------------------------------------------------------- 1 | ' . $file . '.json' . "\n"; 13 | } 14 | 15 | //echo json_encode($all_files); 16 | ?> -------------------------------------------------------------------------------- /songs/script.sh: -------------------------------------------------------------------------------- 1 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-01.spc > Super\ Mario\ World/smw-01.spc.json 2 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-02.spc > Super\ Mario\ World/smw-02.spc.json 3 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-03.spc > Super\ Mario\ World/smw-03.spc.json 4 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-04.spc > Super\ Mario\ World/smw-04.spc.json 5 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-05.spc > Super\ Mario\ World/smw-05.spc.json 6 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-06.spc > Super\ Mario\ World/smw-06.spc.json 7 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-07.spc > Super\ Mario\ World/smw-07.spc.json 8 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-08.spc > Super\ Mario\ World/smw-08.spc.json 9 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-09.spc > Super\ Mario\ World/smw-09.spc.json 10 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-10a.spc > Super\ Mario\ World/smw-10a.spc.json 11 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-10b.spc > Super\ Mario\ World/smw-10b.spc.json 12 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-11a.spc > Super\ Mario\ World/smw-11a.spc.json 13 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-11b.spc > Super\ Mario\ World/smw-11b.spc.json 14 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-11c.spc > Super\ Mario\ World/smw-11c.spc.json 15 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-11d.spc > Super\ Mario\ World/smw-11d.spc.json 16 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-12a.spc > Super\ Mario\ World/smw-12a.spc.json 17 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-12b.spc > Super\ Mario\ World/smw-12b.spc.json 18 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-12c.spc > Super\ Mario\ World/smw-12c.spc.json 19 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-12d.spc > Super\ Mario\ World/smw-12d.spc.json 20 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-13a.spc > Super\ Mario\ World/smw-13a.spc.json 21 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-13b.spc > Super\ Mario\ World/smw-13b.spc.json 22 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-13c.spc > Super\ Mario\ World/smw-13c.spc.json 23 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-13d.spc > Super\ Mario\ World/smw-13d.spc.json 24 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-14a.spc > Super\ Mario\ World/smw-14a.spc.json 25 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-14b.spc > Super\ Mario\ World/smw-14b.spc.json 26 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-14c.spc > Super\ Mario\ World/smw-14c.spc.json 27 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-14d.spc > Super\ Mario\ World/smw-14d.spc.json 28 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-15a.spc > Super\ Mario\ World/smw-15a.spc.json 29 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-15b.spc > Super\ Mario\ World/smw-15b.spc.json 30 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-16a.spc > Super\ Mario\ World/smw-16a.spc.json 31 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-16b.spc > Super\ Mario\ World/smw-16b.spc.json 32 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-17a.spc > Super\ Mario\ World/smw-17a.spc.json 33 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-17b.spc > Super\ Mario\ World/smw-17b.spc.json 34 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-17c.spc > Super\ Mario\ World/smw-17c.spc.json 35 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-17d.spc > Super\ Mario\ World/smw-17d.spc.json 36 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-18a.spc > Super\ Mario\ World/smw-18a.spc.json 37 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-18b.spc > Super\ Mario\ World/smw-18b.spc.json 38 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-18c.spc > Super\ Mario\ World/smw-18c.spc.json 39 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-18d.spc > Super\ Mario\ World/smw-18d.spc.json 40 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-19a.spc > Super\ Mario\ World/smw-19a.spc.json 41 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-19b.spc > Super\ Mario\ World/smw-19b.spc.json 42 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-20.spc > Super\ Mario\ World/smw-20.spc.json 43 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-21a.spc > Super\ Mario\ World/smw-21a.spc.json 44 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-21b.spc > Super\ Mario\ World/smw-21b.spc.json 45 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-22.spc > Super\ Mario\ World/smw-22.spc.json 46 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-23.spc > Super\ Mario\ World/smw-23.spc.json 47 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-24.spc > Super\ Mario\ World/smw-24.spc.json 48 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-25.spc > Super\ Mario\ World/smw-25.spc.json 49 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-26.spc > Super\ Mario\ World/smw-26.spc.json 50 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-27.spc > Super\ Mario\ World/smw-27.spc.json 51 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-28.spc > Super\ Mario\ World/smw-28.spc.json 52 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-29.spc > Super\ Mario\ World/smw-29.spc.json 53 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-30a.spc > Super\ Mario\ World/smw-30a.spc.json 54 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-30b.spc > Super\ Mario\ World/smw-30b.spc.json 55 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-30c.spc > Super\ Mario\ World/smw-30c.spc.json 56 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-30d.spc > Super\ Mario\ World/smw-30d.spc.json 57 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-31a.spc > Super\ Mario\ World/smw-31a.spc.json 58 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-31b.spc > Super\ Mario\ World/smw-31b.spc.json 59 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-32.spc > Super\ Mario\ World/smw-32.spc.json 60 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-33.spc > Super\ Mario\ World/smw-33.spc.json 61 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-34.spc > Super\ Mario\ World/smw-34.spc.json 62 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-35.spc > Super\ Mario\ World/smw-35.spc.json 63 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-36.spc > Super\ Mario\ World/smw-36.spc.json 64 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-37a.spc > Super\ Mario\ World/smw-37a.spc.json 65 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-37b.spc > Super\ Mario\ World/smw-37b.spc.json 66 | python ../../emscripten/tools/file2json.py Super\ Mario\ World/smw-s01.spc > Super\ Mario\ World/smw-s01.spc.json 67 | python ../../emscripten/tools/file2json.py Zelda/loz3-01.spc > Zelda/loz3-01.spc.json 68 | python ../../emscripten/tools/file2json.py Zelda/loz3-02.spc > Zelda/loz3-02.spc.json 69 | python ../../emscripten/tools/file2json.py Zelda/loz3-03.spc > Zelda/loz3-03.spc.json 70 | python ../../emscripten/tools/file2json.py Zelda/loz3-04a.spc > Zelda/loz3-04a.spc.json 71 | python ../../emscripten/tools/file2json.py Zelda/loz3-04b.spc > Zelda/loz3-04b.spc.json 72 | python ../../emscripten/tools/file2json.py Zelda/loz3-05a.spc > Zelda/loz3-05a.spc.json 73 | python ../../emscripten/tools/file2json.py Zelda/loz3-05b.spc > Zelda/loz3-05b.spc.json 74 | python ../../emscripten/tools/file2json.py Zelda/loz3-06.spc > Zelda/loz3-06.spc.json 75 | python ../../emscripten/tools/file2json.py Zelda/loz3-07.spc > Zelda/loz3-07.spc.json 76 | python ../../emscripten/tools/file2json.py Zelda/loz3-08.spc > Zelda/loz3-08.spc.json 77 | python ../../emscripten/tools/file2json.py Zelda/loz3-09.spc > Zelda/loz3-09.spc.json 78 | python ../../emscripten/tools/file2json.py Zelda/loz3-10.spc > Zelda/loz3-10.spc.json 79 | python ../../emscripten/tools/file2json.py Zelda/loz3-11.spc > Zelda/loz3-11.spc.json 80 | python ../../emscripten/tools/file2json.py Zelda/loz3-12.spc > Zelda/loz3-12.spc.json 81 | python ../../emscripten/tools/file2json.py Zelda/loz3-13.spc > Zelda/loz3-13.spc.json 82 | python ../../emscripten/tools/file2json.py Zelda/loz3-14.spc > Zelda/loz3-14.spc.json 83 | python ../../emscripten/tools/file2json.py Zelda/loz3-15.spc > Zelda/loz3-15.spc.json 84 | python ../../emscripten/tools/file2json.py Zelda/loz3-16.spc > Zelda/loz3-16.spc.json 85 | python ../../emscripten/tools/file2json.py Zelda/loz3-17a.spc > Zelda/loz3-17a.spc.json 86 | python ../../emscripten/tools/file2json.py Zelda/loz3-17b.spc > Zelda/loz3-17b.spc.json 87 | python ../../emscripten/tools/file2json.py Zelda/loz3-18.spc > Zelda/loz3-18.spc.json 88 | python ../../emscripten/tools/file2json.py Zelda/loz3-19.spc > Zelda/loz3-19.spc.json 89 | python ../../emscripten/tools/file2json.py Zelda/loz3-20.spc > Zelda/loz3-20.spc.json 90 | python ../../emscripten/tools/file2json.py Zelda/loz3-21.spc > Zelda/loz3-21.spc.json 91 | python ../../emscripten/tools/file2json.py Zelda/loz3-22a.spc > Zelda/loz3-22a.spc.json 92 | python ../../emscripten/tools/file2json.py Zelda/loz3-22b.spc > Zelda/loz3-22b.spc.json 93 | python ../../emscripten/tools/file2json.py Zelda/loz3-23.spc > Zelda/loz3-23.spc.json 94 | python ../../emscripten/tools/file2json.py Zelda/loz3-24.spc > Zelda/loz3-24.spc.json 95 | python ../../emscripten/tools/file2json.py Zelda/loz3-25.spc > Zelda/loz3-25.spc.json 96 | python ../../emscripten/tools/file2json.py Zelda/loz3-26.spc > Zelda/loz3-26.spc.json 97 | python ../../emscripten/tools/file2json.py Zelda/loz3-27.spc > Zelda/loz3-27.spc.json 98 | python ../../emscripten/tools/file2json.py Zelda/loz3-28.spc > Zelda/loz3-28.spc.json 99 | python ../../emscripten/tools/file2json.py Zelda/loz3-29.spc > Zelda/loz3-29.spc.json 100 | python ../../emscripten/tools/file2json.py Zelda/loz3-30.spc > Zelda/loz3-30.spc.json 101 | python ../../emscripten/tools/file2json.py Zelda/loz3-31.spc > Zelda/loz3-31.spc.json 102 | python ../../emscripten/tools/file2json.py Zelda/loz3-b01.spc > Zelda/loz3-b01.spc.json 103 | python ../../emscripten/tools/file2json.py Zelda/loz3-b02.spc > Zelda/loz3-b02.spc.json 104 | python ../../emscripten/tools/file2json.py Zelda/loz3-b03.spc > Zelda/loz3-b03.spc.json 105 | python ../../emscripten/tools/file2json.py Zelda/loz3-s01.spc > Zelda/loz3-s01.spc.json 106 | python ../../emscripten/tools/file2json.py Zelda/loz3-s02.spc > Zelda/loz3-s02.spc.json 107 | python ../../emscripten/tools/file2json.py Zelda/loz3-s03.spc > Zelda/loz3-s03.spc.json 108 | python ../../emscripten/tools/file2json.py Zelda/loz3-s04.spc > Zelda/loz3-s04.spc.json 109 | python ../../emscripten/tools/file2json.py Zelda/loz3-s05.spc > Zelda/loz3-s05.spc.json 110 | python ../../emscripten/tools/file2json.py Zelda/loz3-s06.spc > Zelda/loz3-s06.spc.json 111 | python ../../emscripten/tools/file2json.py Zelda/loz3-s07.spc > Zelda/loz3-s07.spc.json 112 | python ../../emscripten/tools/file2json.py Zelda/loz3-s08a.spc > Zelda/loz3-s08a.spc.json 113 | python ../../emscripten/tools/file2json.py Zelda/loz3-s08b.spc > Zelda/loz3-s08b.spc.json 114 | python ../../emscripten/tools/file2json.py Zelda/loz3-s09.spc > Zelda/loz3-s09.spc.json 115 | python ../../emscripten/tools/file2json.py Zelda/loz3-s10.spc > Zelda/loz3-s10.spc.json 116 | python ../../emscripten/tools/file2json.py Zelda/loz3-s11.spc > Zelda/loz3-s11.spc.json 117 | --------------------------------------------------------------------------------