| @@ -278,6 +278,21 @@ struct MomentarySwitch : virtual Switch { | |||
| } | |||
| }; | |||
| //////////////////// | |||
| // IO widgets | |||
| //////////////////// | |||
| struct AudioIO; | |||
| struct AudioWidget : OpaqueWidget { | |||
| /** Not owned */ | |||
| AudioIO *audioIO = NULL; | |||
| void onMouseDown(EventMouseDown &e) override; | |||
| }; | |||
| struct MIDIWidget : OpaqueWidget { | |||
| }; | |||
| //////////////////// | |||
| // lights | |||
| //////////////////// | |||
| @@ -0,0 +1,42 @@ | |||
| #pragma once | |||
| #pragma GCC diagnostic push | |||
| #pragma GCC diagnostic ignored "-Wsuggest-override" | |||
| #include <RtAudio.h> | |||
| #pragma GCC diagnostic pop | |||
| namespace rack { | |||
| struct AudioIO { | |||
| int maxOutputs = 8; | |||
| int maxInputs = 8; | |||
| RtAudio *stream = NULL; | |||
| // Stream properties | |||
| int device = -1; | |||
| int sampleRate = 44100; | |||
| int blockSize = 256; | |||
| int numOutputs = 0; | |||
| int numInputs = 0; | |||
| AudioIO(); | |||
| ~AudioIO(); | |||
| std::vector<int> listDrivers(); | |||
| std::string getDriverName(int driver); | |||
| int getDriver(); | |||
| void setDriver(int driver); | |||
| int getDeviceCount(); | |||
| std::string getDeviceName(int device); | |||
| std::string getDeviceDetail(int device); | |||
| void openStream(); | |||
| void closeStream(); | |||
| std::vector<int> listSampleRates(); | |||
| }; | |||
| } // namespace rack | |||
| @@ -336,6 +336,22 @@ struct BefacoSlidePot : SVGFader { | |||
| } | |||
| }; | |||
| //////////////////// | |||
| // IO widgets | |||
| //////////////////// | |||
| struct USB_B_AudioWidget : AudioWidget, SVGWidget { | |||
| USB_B_AudioWidget() { | |||
| setSVG(SVG::load(assetGlobal("res/ComponentLibrary/USB-B.svg"))); | |||
| } | |||
| }; | |||
| struct DIN_MIDIWidget : MIDIWidget, SVGWidget { | |||
| DIN_MIDIWidget() { | |||
| setSVG(SVG::load(assetGlobal("res/ComponentLibrary/MIDI_DIN.svg"))); | |||
| } | |||
| }; | |||
| //////////////////// | |||
| // Jacks | |||
| //////////////////// | |||
| @@ -7,7 +7,7 @@ | |||
| #include "engine.hpp" | |||
| #include "gui.hpp" | |||
| #include "app.hpp" | |||
| #include "components.hpp" | |||
| #include "componentlibrary.hpp" | |||
| namespace rack { | |||
| @@ -25,6 +25,9 @@ inline Vec mm2px(Vec millimeters) { | |||
| return millimeters.mult(SVG_DPI / 25.4); | |||
| } | |||
| #define CHECKMARK_STRING "âś”" | |||
| #define CHECKMARK(_cond) ((_cond) ? CHECKMARK_STRING : "") | |||
| //////////////////// | |||
| // resources | |||
| @@ -0,0 +1,366 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
| <svg | |||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
| xmlns:cc="http://creativecommons.org/ns#" | |||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
| xmlns:svg="http://www.w3.org/2000/svg" | |||
| xmlns="http://www.w3.org/2000/svg" | |||
| xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
| xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
| width="10.415202mm" | |||
| height="10.667406mm" | |||
| viewBox="0 0 10.415202 10.667406" | |||
| version="1.1" | |||
| id="svg8104" | |||
| inkscape:version="0.92.2 5c3e80d, 2017-08-06" | |||
| sodipodi:docname="ADAT.svg"> | |||
| <defs | |||
| id="defs8098"> | |||
| <clipPath | |||
| id="clip306"> | |||
| <path | |||
| d="m 1550,2365 h 44 v 44 h -44 z m 0,0" | |||
| id="path6964" | |||
| inkscape:connector-curvature="0" /> | |||
| </clipPath> | |||
| <clipPath | |||
| id="clip307"> | |||
| <path | |||
| d="m 1550.0859,2386.6914 c 0,11.8867 9.6368,21.5274 21.5274,21.5274 11.8906,0 21.5273,-9.6407 21.5273,-21.5274 0,-11.8906 -9.6367,-21.5312 -21.5273,-21.5312 -11.8906,0 -21.5274,9.6406 -21.5274,21.5312" | |||
| id="path6967" | |||
| inkscape:connector-curvature="0" /> | |||
| </clipPath> | |||
| <linearGradient | |||
| id="linear3" | |||
| gradientUnits="userSpaceOnUse" | |||
| x1="-0.0115906" | |||
| y1="0" | |||
| x2="0.985816" | |||
| y2="0" | |||
| gradientTransform="matrix(0,43.168976,-43.168976,0,1571.6138,2365.6624)"> | |||
| <stop | |||
| offset="0" | |||
| style="stop-color:rgb(32.940674%,32.940674%,33.724976%);stop-opacity:1;" | |||
| id="stop6970" /> | |||
| <stop | |||
| offset="0.03125" | |||
| style="stop-color:rgb(32.814026%,32.806396%,33.586121%);stop-opacity:1;" | |||
| id="stop6972" /> | |||
| <stop | |||
| offset="0.046875" | |||
| style="stop-color:rgb(32.58667%,32.565308%,33.338928%);stop-opacity:1;" | |||
| id="stop6974" /> | |||
| <stop | |||
| offset="0.0625" | |||
| style="stop-color:rgb(32.383728%,32.350159%,33.117676%);stop-opacity:1;" | |||
| id="stop6976" /> | |||
| <stop | |||
| offset="0.078125" | |||
| style="stop-color:rgb(32.182312%,32.136536%,32.897949%);stop-opacity:1;" | |||
| id="stop6978" /> | |||
| <stop | |||
| offset="0.09375" | |||
| style="stop-color:rgb(31.980896%,31.922913%,32.678223%);stop-opacity:1;" | |||
| id="stop6980" /> | |||
| <stop | |||
| offset="0.109375" | |||
| style="stop-color:rgb(31.77948%,31.70929%,32.458496%);stop-opacity:1;" | |||
| id="stop6982" /> | |||
| <stop | |||
| offset="0.125" | |||
| style="stop-color:rgb(31.578064%,31.495667%,32.23877%);stop-opacity:1;" | |||
| id="stop6984" /> | |||
| <stop | |||
| offset="0.140625" | |||
| style="stop-color:rgb(31.376648%,31.280518%,32.017517%);stop-opacity:1;" | |||
| id="stop6986" /> | |||
| <stop | |||
| offset="0.15625" | |||
| style="stop-color:rgb(31.173706%,31.066895%,31.797791%);stop-opacity:1;" | |||
| id="stop6988" /> | |||
| <stop | |||
| offset="0.171875" | |||
| style="stop-color:rgb(30.97229%,30.853271%,31.578064%);stop-opacity:1;" | |||
| id="stop6990" /> | |||
| <stop | |||
| offset="0.1875" | |||
| style="stop-color:rgb(30.770874%,30.639648%,31.358337%);stop-opacity:1;" | |||
| id="stop6992" /> | |||
| <stop | |||
| offset="0.203125" | |||
| style="stop-color:rgb(30.569458%,30.426025%,31.138611%);stop-opacity:1;" | |||
| id="stop6994" /> | |||
| <stop | |||
| offset="0.21875" | |||
| style="stop-color:rgb(30.368042%,30.212402%,30.917358%);stop-opacity:1;" | |||
| id="stop6996" /> | |||
| <stop | |||
| offset="0.234375" | |||
| style="stop-color:rgb(30.166626%,29.997253%,30.697632%);stop-opacity:1;" | |||
| id="stop6998" /> | |||
| <stop | |||
| offset="0.25" | |||
| style="stop-color:rgb(29.963684%,29.78363%,30.477905%);stop-opacity:1;" | |||
| id="stop7000" /> | |||
| <stop | |||
| offset="0.265625" | |||
| style="stop-color:rgb(29.762268%,29.570007%,30.258179%);stop-opacity:1;" | |||
| id="stop7002" /> | |||
| <stop | |||
| offset="0.28125" | |||
| style="stop-color:rgb(29.560852%,29.356384%,30.038452%);stop-opacity:1;" | |||
| id="stop7004" /> | |||
| <stop | |||
| offset="0.296875" | |||
| style="stop-color:rgb(29.359436%,29.142761%,29.8172%);stop-opacity:1;" | |||
| id="stop7006" /> | |||
| <stop | |||
| offset="0.3125" | |||
| style="stop-color:rgb(29.15802%,28.927612%,29.597473%);stop-opacity:1;" | |||
| id="stop7008" /> | |||
| <stop | |||
| offset="0.328125" | |||
| style="stop-color:rgb(28.955078%,28.713989%,29.377747%);stop-opacity:1;" | |||
| id="stop7010" /> | |||
| <stop | |||
| offset="0.34375" | |||
| style="stop-color:rgb(28.753662%,28.500366%,29.15802%);stop-opacity:1;" | |||
| id="stop7012" /> | |||
| <stop | |||
| offset="0.359375" | |||
| style="stop-color:rgb(28.552246%,28.286743%,28.938293%);stop-opacity:1;" | |||
| id="stop7014" /> | |||
| <stop | |||
| offset="0.375" | |||
| style="stop-color:rgb(28.35083%,28.07312%,28.718567%);stop-opacity:1;" | |||
| id="stop7016" /> | |||
| <stop | |||
| offset="0.390625" | |||
| style="stop-color:rgb(28.149414%,27.857971%,28.497314%);stop-opacity:1;" | |||
| id="stop7018" /> | |||
| <stop | |||
| offset="0.40625" | |||
| style="stop-color:rgb(27.947998%,27.644348%,28.277588%);stop-opacity:1;" | |||
| id="stop7020" /> | |||
| <stop | |||
| offset="0.421875" | |||
| style="stop-color:rgb(27.745056%,27.430725%,28.057861%);stop-opacity:1;" | |||
| id="stop7022" /> | |||
| <stop | |||
| offset="0.4375" | |||
| style="stop-color:rgb(27.54364%,27.217102%,27.838135%);stop-opacity:1;" | |||
| id="stop7024" /> | |||
| <stop | |||
| offset="0.453125" | |||
| style="stop-color:rgb(27.342224%,27.003479%,27.618408%);stop-opacity:1;" | |||
| id="stop7026" /> | |||
| <stop | |||
| offset="0.46875" | |||
| style="stop-color:rgb(27.140808%,26.789856%,27.397156%);stop-opacity:1;" | |||
| id="stop7028" /> | |||
| <stop | |||
| offset="0.484375" | |||
| style="stop-color:rgb(26.939392%,26.574707%,27.177429%);stop-opacity:1;" | |||
| id="stop7030" /> | |||
| <stop | |||
| offset="0.5" | |||
| style="stop-color:rgb(26.737976%,26.361084%,26.957703%);stop-opacity:1;" | |||
| id="stop7032" /> | |||
| <stop | |||
| offset="0.515625" | |||
| style="stop-color:rgb(26.535034%,26.147461%,26.737976%);stop-opacity:1;" | |||
| id="stop7034" /> | |||
| <stop | |||
| offset="0.53125" | |||
| style="stop-color:rgb(26.333618%,25.933838%,26.51825%);stop-opacity:1;" | |||
| id="stop7036" /> | |||
| <stop | |||
| offset="0.546875" | |||
| style="stop-color:rgb(26.132202%,25.720215%,26.296997%);stop-opacity:1;" | |||
| id="stop7038" /> | |||
| <stop | |||
| offset="0.5625" | |||
| style="stop-color:rgb(25.930786%,25.505066%,26.077271%);stop-opacity:1;" | |||
| id="stop7040" /> | |||
| <stop | |||
| offset="0.578125" | |||
| style="stop-color:rgb(25.72937%,25.291443%,25.857544%);stop-opacity:1;" | |||
| id="stop7042" /> | |||
| <stop | |||
| offset="0.59375" | |||
| style="stop-color:rgb(25.527954%,25.07782%,25.637817%);stop-opacity:1;" | |||
| id="stop7044" /> | |||
| <stop | |||
| offset="0.609375" | |||
| style="stop-color:rgb(25.325012%,24.864197%,25.418091%);stop-opacity:1;" | |||
| id="stop7046" /> | |||
| <stop | |||
| offset="0.625" | |||
| style="stop-color:rgb(25.123596%,24.650574%,25.196838%);stop-opacity:1;" | |||
| id="stop7048" /> | |||
| <stop | |||
| offset="0.640625" | |||
| style="stop-color:rgb(24.92218%,24.436951%,24.977112%);stop-opacity:1;" | |||
| id="stop7050" /> | |||
| <stop | |||
| offset="0.65625" | |||
| style="stop-color:rgb(24.720764%,24.221802%,24.757385%);stop-opacity:1;" | |||
| id="stop7052" /> | |||
| <stop | |||
| offset="0.671875" | |||
| style="stop-color:rgb(24.519348%,24.008179%,24.537659%);stop-opacity:1;" | |||
| id="stop7054" /> | |||
| <stop | |||
| offset="0.6875" | |||
| style="stop-color:rgb(24.316406%,23.794556%,24.317932%);stop-opacity:1;" | |||
| id="stop7056" /> | |||
| <stop | |||
| offset="0.703125" | |||
| style="stop-color:rgb(24.11499%,23.580933%,24.098206%);stop-opacity:1;" | |||
| id="stop7058" /> | |||
| <stop | |||
| offset="0.71875" | |||
| style="stop-color:rgb(23.913574%,23.36731%,23.876953%);stop-opacity:1;" | |||
| id="stop7060" /> | |||
| <stop | |||
| offset="0.734375" | |||
| style="stop-color:rgb(23.712158%,23.152161%,23.657227%);stop-opacity:1;" | |||
| id="stop7062" /> | |||
| <stop | |||
| offset="0.75" | |||
| style="stop-color:rgb(23.510742%,22.938538%,23.4375%);stop-opacity:1;" | |||
| id="stop7064" /> | |||
| <stop | |||
| offset="0.765625" | |||
| style="stop-color:rgb(23.309326%,22.724915%,23.217773%);stop-opacity:1;" | |||
| id="stop7066" /> | |||
| <stop | |||
| offset="0.78125" | |||
| style="stop-color:rgb(23.106384%,22.511292%,22.998047%);stop-opacity:1;" | |||
| id="stop7068" /> | |||
| <stop | |||
| offset="0.796875" | |||
| style="stop-color:rgb(22.904968%,22.297668%,22.776794%);stop-opacity:1;" | |||
| id="stop7070" /> | |||
| <stop | |||
| offset="0.8125" | |||
| style="stop-color:rgb(22.703552%,22.084045%,22.557068%);stop-opacity:1;" | |||
| id="stop7072" /> | |||
| <stop | |||
| offset="0.828125" | |||
| style="stop-color:rgb(22.502136%,21.868896%,22.337341%);stop-opacity:1;" | |||
| id="stop7074" /> | |||
| <stop | |||
| offset="0.84375" | |||
| style="stop-color:rgb(22.30072%,21.655273%,22.117615%);stop-opacity:1;" | |||
| id="stop7076" /> | |||
| <stop | |||
| offset="0.859375" | |||
| style="stop-color:rgb(22.099304%,21.44165%,21.897888%);stop-opacity:1;" | |||
| id="stop7078" /> | |||
| <stop | |||
| offset="0.875" | |||
| style="stop-color:rgb(21.896362%,21.228027%,21.676636%);stop-opacity:1;" | |||
| id="stop7080" /> | |||
| <stop | |||
| offset="0.890625" | |||
| style="stop-color:rgb(21.694946%,21.014404%,21.456909%);stop-opacity:1;" | |||
| id="stop7082" /> | |||
| <stop | |||
| offset="0.90625" | |||
| style="stop-color:rgb(21.49353%,20.799255%,21.237183%);stop-opacity:1;" | |||
| id="stop7084" /> | |||
| <stop | |||
| offset="0.921875" | |||
| style="stop-color:rgb(21.292114%,20.585632%,21.017456%);stop-opacity:1;" | |||
| id="stop7086" /> | |||
| <stop | |||
| offset="0.9375" | |||
| style="stop-color:rgb(21.090698%,20.372009%,20.797729%);stop-opacity:1;" | |||
| id="stop7088" /> | |||
| <stop | |||
| offset="0.953125" | |||
| style="stop-color:rgb(20.889282%,20.158386%,20.576477%);stop-opacity:1;" | |||
| id="stop7090" /> | |||
| <stop | |||
| offset="0.96875" | |||
| style="stop-color:rgb(20.68634%,19.944763%,20.35675%);stop-opacity:1;" | |||
| id="stop7092" /> | |||
| <stop | |||
| offset="0.984375" | |||
| style="stop-color:rgb(20.484924%,19.729614%,20.137024%);stop-opacity:1;" | |||
| id="stop7094" /> | |||
| <stop | |||
| offset="1" | |||
| style="stop-color:rgb(20.283508%,19.515991%,19.917297%);stop-opacity:1;" | |||
| id="stop7096" /> | |||
| </linearGradient> | |||
| </defs> | |||
| <sodipodi:namedview | |||
| id="base" | |||
| pagecolor="#ffffff" | |||
| bordercolor="#666666" | |||
| borderopacity="1.0" | |||
| inkscape:pageopacity="0.0" | |||
| inkscape:pageshadow="2" | |||
| inkscape:zoom="1.979899" | |||
| inkscape:cx="171.96332" | |||
| inkscape:cy="-12.111977" | |||
| inkscape:document-units="mm" | |||
| inkscape:current-layer="layer1" | |||
| showgrid="false" | |||
| fit-margin-top="0" | |||
| fit-margin-left="0" | |||
| fit-margin-right="0" | |||
| fit-margin-bottom="0" | |||
| inkscape:window-width="1600" | |||
| inkscape:window-height="882" | |||
| inkscape:window-x="0" | |||
| inkscape:window-y="18" | |||
| inkscape:window-maximized="0" /> | |||
| <metadata | |||
| id="metadata8101"> | |||
| <rdf:RDF> | |||
| <cc:Work | |||
| rdf:about=""> | |||
| <dc:format>image/svg+xml</dc:format> | |||
| <dc:type | |||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
| <dc:title></dc:title> | |||
| </cc:Work> | |||
| </rdf:RDF> | |||
| </metadata> | |||
| <g | |||
| inkscape:label="Layer 1" | |||
| inkscape:groupmode="layer" | |||
| id="layer1" | |||
| transform="translate(-98.481578,-96.351604)"> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10049" | |||
| d="m 108.89678,106.51189 c 0,0.27838 -0.22874,0.50712 -0.50849,0.50712 h -9.398222 c -0.27837,0 -0.50849,-0.22874 -0.50849,-0.50712 v -9.398215 c 0,-0.279753 0.23012,-0.507119 0.50849,-0.507119 h 9.398222 c 0.27975,0 0.50849,0.227366 0.50849,0.507119 z m 0,0" | |||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10051" | |||
| d="m 108.89678,106.25831 c 0,0.27838 -0.22874,0.50712 -0.50849,0.50712 h -9.398222 c -0.27837,0 -0.50849,-0.22874 -0.50849,-0.50712 v -9.398212 c 0,-0.279718 0.23012,-0.508494 0.50849,-0.508494 h 9.398222 c 0.27975,0 0.50849,0.228776 0.50849,0.508494 z m 0,0" | |||
| style="fill:#424242;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10053" | |||
| d="m 106.72501,98.389742 h -3.61735 l -0.55813,0.617361 h -0.82956 l -1.06662,1.014237 v 3.07164 l 1.06662,1.06521 h 0.82956 l 0.55813,0.57051 h 3.61735 z m 0,0" | |||
| style="fill:#211e1e;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10055" | |||
| d="m 103.00155,104.98228 -0.5581,-0.56914 h -0.82959 l -1.21405,-1.21542 v -3.285248 l 1.21818,-1.158945 h 0.81855 l 0.5595,-0.617361 h 3.98251 v 6.846114 z m 0,0" | |||
| style="fill:#211e1e;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10057" | |||
| d="m 106.72501,98.389742 h -3.61735 l -0.55813,0.617361 h -0.82956 l -1.06662,1.014237 v 3.07164 l 1.06662,1.06521 h 0.82956 l 0.55813,0.57051 h 3.61735 z m 0,0" | |||
| style="fill:#424242;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| </g> | |||
| </svg> | |||
| @@ -0,0 +1,397 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
| <svg | |||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
| xmlns:cc="http://creativecommons.org/ns#" | |||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
| xmlns:svg="http://www.w3.org/2000/svg" | |||
| xmlns="http://www.w3.org/2000/svg" | |||
| xmlns:xlink="http://www.w3.org/1999/xlink" | |||
| xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
| xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
| width="16.999479mm" | |||
| height="17.000858mm" | |||
| viewBox="0 0 16.999479 17.000858" | |||
| version="1.1" | |||
| id="svg8104" | |||
| inkscape:version="0.92.2 5c3e80d, 2017-08-06" | |||
| sodipodi:docname="MIDI_DIN.svg"> | |||
| <defs | |||
| id="defs8098"> | |||
| <linearGradient | |||
| inkscape:collect="always" | |||
| id="linearGradient1258"> | |||
| <stop | |||
| style="stop-color:#545456;stop-opacity:1" | |||
| offset="0" | |||
| id="stop1254" /> | |||
| <stop | |||
| style="stop-color:#333132;stop-opacity:1" | |||
| offset="1" | |||
| id="stop1256" /> | |||
| </linearGradient> | |||
| <clipPath | |||
| id="clip306"> | |||
| <path | |||
| d="m 1550,2365 h 44 v 44 h -44 z m 0,0" | |||
| id="path6964" | |||
| inkscape:connector-curvature="0" /> | |||
| </clipPath> | |||
| <linearGradient | |||
| id="linear3" | |||
| gradientUnits="userSpaceOnUse" | |||
| x1="-0.0115906" | |||
| y1="0" | |||
| x2="0.985816" | |||
| y2="0" | |||
| gradientTransform="matrix(0,43.168976,-43.168976,0,1571.6138,2365.6624)"> | |||
| <stop | |||
| offset="0" | |||
| style="stop-color:rgb(32.940674%,32.940674%,33.724976%);stop-opacity:1;" | |||
| id="stop6970" /> | |||
| <stop | |||
| offset="0.03125" | |||
| style="stop-color:rgb(32.814026%,32.806396%,33.586121%);stop-opacity:1;" | |||
| id="stop6972" /> | |||
| <stop | |||
| offset="0.046875" | |||
| style="stop-color:rgb(32.58667%,32.565308%,33.338928%);stop-opacity:1;" | |||
| id="stop6974" /> | |||
| <stop | |||
| offset="0.0625" | |||
| style="stop-color:rgb(32.383728%,32.350159%,33.117676%);stop-opacity:1;" | |||
| id="stop6976" /> | |||
| <stop | |||
| offset="0.078125" | |||
| style="stop-color:rgb(32.182312%,32.136536%,32.897949%);stop-opacity:1;" | |||
| id="stop6978" /> | |||
| <stop | |||
| offset="0.09375" | |||
| style="stop-color:rgb(31.980896%,31.922913%,32.678223%);stop-opacity:1;" | |||
| id="stop6980" /> | |||
| <stop | |||
| offset="0.109375" | |||
| style="stop-color:rgb(31.77948%,31.70929%,32.458496%);stop-opacity:1;" | |||
| id="stop6982" /> | |||
| <stop | |||
| offset="0.125" | |||
| style="stop-color:rgb(31.578064%,31.495667%,32.23877%);stop-opacity:1;" | |||
| id="stop6984" /> | |||
| <stop | |||
| offset="0.140625" | |||
| style="stop-color:rgb(31.376648%,31.280518%,32.017517%);stop-opacity:1;" | |||
| id="stop6986" /> | |||
| <stop | |||
| offset="0.15625" | |||
| style="stop-color:rgb(31.173706%,31.066895%,31.797791%);stop-opacity:1;" | |||
| id="stop6988" /> | |||
| <stop | |||
| offset="0.171875" | |||
| style="stop-color:rgb(30.97229%,30.853271%,31.578064%);stop-opacity:1;" | |||
| id="stop6990" /> | |||
| <stop | |||
| offset="0.1875" | |||
| style="stop-color:rgb(30.770874%,30.639648%,31.358337%);stop-opacity:1;" | |||
| id="stop6992" /> | |||
| <stop | |||
| offset="0.203125" | |||
| style="stop-color:rgb(30.569458%,30.426025%,31.138611%);stop-opacity:1;" | |||
| id="stop6994" /> | |||
| <stop | |||
| offset="0.21875" | |||
| style="stop-color:rgb(30.368042%,30.212402%,30.917358%);stop-opacity:1;" | |||
| id="stop6996" /> | |||
| <stop | |||
| offset="0.234375" | |||
| style="stop-color:rgb(30.166626%,29.997253%,30.697632%);stop-opacity:1;" | |||
| id="stop6998" /> | |||
| <stop | |||
| offset="0.25" | |||
| style="stop-color:rgb(29.963684%,29.78363%,30.477905%);stop-opacity:1;" | |||
| id="stop7000" /> | |||
| <stop | |||
| offset="0.265625" | |||
| style="stop-color:rgb(29.762268%,29.570007%,30.258179%);stop-opacity:1;" | |||
| id="stop7002" /> | |||
| <stop | |||
| offset="0.28125" | |||
| style="stop-color:rgb(29.560852%,29.356384%,30.038452%);stop-opacity:1;" | |||
| id="stop7004" /> | |||
| <stop | |||
| offset="0.296875" | |||
| style="stop-color:rgb(29.359436%,29.142761%,29.8172%);stop-opacity:1;" | |||
| id="stop7006" /> | |||
| <stop | |||
| offset="0.3125" | |||
| style="stop-color:rgb(29.15802%,28.927612%,29.597473%);stop-opacity:1;" | |||
| id="stop7008" /> | |||
| <stop | |||
| offset="0.328125" | |||
| style="stop-color:rgb(28.955078%,28.713989%,29.377747%);stop-opacity:1;" | |||
| id="stop7010" /> | |||
| <stop | |||
| offset="0.34375" | |||
| style="stop-color:rgb(28.753662%,28.500366%,29.15802%);stop-opacity:1;" | |||
| id="stop7012" /> | |||
| <stop | |||
| offset="0.359375" | |||
| style="stop-color:rgb(28.552246%,28.286743%,28.938293%);stop-opacity:1;" | |||
| id="stop7014" /> | |||
| <stop | |||
| offset="0.375" | |||
| style="stop-color:rgb(28.35083%,28.07312%,28.718567%);stop-opacity:1;" | |||
| id="stop7016" /> | |||
| <stop | |||
| offset="0.390625" | |||
| style="stop-color:rgb(28.149414%,27.857971%,28.497314%);stop-opacity:1;" | |||
| id="stop7018" /> | |||
| <stop | |||
| offset="0.40625" | |||
| style="stop-color:rgb(27.947998%,27.644348%,28.277588%);stop-opacity:1;" | |||
| id="stop7020" /> | |||
| <stop | |||
| offset="0.421875" | |||
| style="stop-color:rgb(27.745056%,27.430725%,28.057861%);stop-opacity:1;" | |||
| id="stop7022" /> | |||
| <stop | |||
| offset="0.4375" | |||
| style="stop-color:rgb(27.54364%,27.217102%,27.838135%);stop-opacity:1;" | |||
| id="stop7024" /> | |||
| <stop | |||
| offset="0.453125" | |||
| style="stop-color:rgb(27.342224%,27.003479%,27.618408%);stop-opacity:1;" | |||
| id="stop7026" /> | |||
| <stop | |||
| offset="0.46875" | |||
| style="stop-color:rgb(27.140808%,26.789856%,27.397156%);stop-opacity:1;" | |||
| id="stop7028" /> | |||
| <stop | |||
| offset="0.484375" | |||
| style="stop-color:rgb(26.939392%,26.574707%,27.177429%);stop-opacity:1;" | |||
| id="stop7030" /> | |||
| <stop | |||
| offset="0.5" | |||
| style="stop-color:rgb(26.737976%,26.361084%,26.957703%);stop-opacity:1;" | |||
| id="stop7032" /> | |||
| <stop | |||
| offset="0.515625" | |||
| style="stop-color:rgb(26.535034%,26.147461%,26.737976%);stop-opacity:1;" | |||
| id="stop7034" /> | |||
| <stop | |||
| offset="0.53125" | |||
| style="stop-color:rgb(26.333618%,25.933838%,26.51825%);stop-opacity:1;" | |||
| id="stop7036" /> | |||
| <stop | |||
| offset="0.546875" | |||
| style="stop-color:rgb(26.132202%,25.720215%,26.296997%);stop-opacity:1;" | |||
| id="stop7038" /> | |||
| <stop | |||
| offset="0.5625" | |||
| style="stop-color:rgb(25.930786%,25.505066%,26.077271%);stop-opacity:1;" | |||
| id="stop7040" /> | |||
| <stop | |||
| offset="0.578125" | |||
| style="stop-color:rgb(25.72937%,25.291443%,25.857544%);stop-opacity:1;" | |||
| id="stop7042" /> | |||
| <stop | |||
| offset="0.59375" | |||
| style="stop-color:rgb(25.527954%,25.07782%,25.637817%);stop-opacity:1;" | |||
| id="stop7044" /> | |||
| <stop | |||
| offset="0.609375" | |||
| style="stop-color:rgb(25.325012%,24.864197%,25.418091%);stop-opacity:1;" | |||
| id="stop7046" /> | |||
| <stop | |||
| offset="0.625" | |||
| style="stop-color:rgb(25.123596%,24.650574%,25.196838%);stop-opacity:1;" | |||
| id="stop7048" /> | |||
| <stop | |||
| offset="0.640625" | |||
| style="stop-color:rgb(24.92218%,24.436951%,24.977112%);stop-opacity:1;" | |||
| id="stop7050" /> | |||
| <stop | |||
| offset="0.65625" | |||
| style="stop-color:rgb(24.720764%,24.221802%,24.757385%);stop-opacity:1;" | |||
| id="stop7052" /> | |||
| <stop | |||
| offset="0.671875" | |||
| style="stop-color:rgb(24.519348%,24.008179%,24.537659%);stop-opacity:1;" | |||
| id="stop7054" /> | |||
| <stop | |||
| offset="0.6875" | |||
| style="stop-color:rgb(24.316406%,23.794556%,24.317932%);stop-opacity:1;" | |||
| id="stop7056" /> | |||
| <stop | |||
| offset="0.703125" | |||
| style="stop-color:rgb(24.11499%,23.580933%,24.098206%);stop-opacity:1;" | |||
| id="stop7058" /> | |||
| <stop | |||
| offset="0.71875" | |||
| style="stop-color:rgb(23.913574%,23.36731%,23.876953%);stop-opacity:1;" | |||
| id="stop7060" /> | |||
| <stop | |||
| offset="0.734375" | |||
| style="stop-color:rgb(23.712158%,23.152161%,23.657227%);stop-opacity:1;" | |||
| id="stop7062" /> | |||
| <stop | |||
| offset="0.75" | |||
| style="stop-color:rgb(23.510742%,22.938538%,23.4375%);stop-opacity:1;" | |||
| id="stop7064" /> | |||
| <stop | |||
| offset="0.765625" | |||
| style="stop-color:rgb(23.309326%,22.724915%,23.217773%);stop-opacity:1;" | |||
| id="stop7066" /> | |||
| <stop | |||
| offset="0.78125" | |||
| style="stop-color:rgb(23.106384%,22.511292%,22.998047%);stop-opacity:1;" | |||
| id="stop7068" /> | |||
| <stop | |||
| offset="0.796875" | |||
| style="stop-color:rgb(22.904968%,22.297668%,22.776794%);stop-opacity:1;" | |||
| id="stop7070" /> | |||
| <stop | |||
| offset="0.8125" | |||
| style="stop-color:rgb(22.703552%,22.084045%,22.557068%);stop-opacity:1;" | |||
| id="stop7072" /> | |||
| <stop | |||
| offset="0.828125" | |||
| style="stop-color:rgb(22.502136%,21.868896%,22.337341%);stop-opacity:1;" | |||
| id="stop7074" /> | |||
| <stop | |||
| offset="0.84375" | |||
| style="stop-color:rgb(22.30072%,21.655273%,22.117615%);stop-opacity:1;" | |||
| id="stop7076" /> | |||
| <stop | |||
| offset="0.859375" | |||
| style="stop-color:rgb(22.099304%,21.44165%,21.897888%);stop-opacity:1;" | |||
| id="stop7078" /> | |||
| <stop | |||
| offset="0.875" | |||
| style="stop-color:rgb(21.896362%,21.228027%,21.676636%);stop-opacity:1;" | |||
| id="stop7080" /> | |||
| <stop | |||
| offset="0.890625" | |||
| style="stop-color:rgb(21.694946%,21.014404%,21.456909%);stop-opacity:1;" | |||
| id="stop7082" /> | |||
| <stop | |||
| offset="0.90625" | |||
| style="stop-color:rgb(21.49353%,20.799255%,21.237183%);stop-opacity:1;" | |||
| id="stop7084" /> | |||
| <stop | |||
| offset="0.921875" | |||
| style="stop-color:rgb(21.292114%,20.585632%,21.017456%);stop-opacity:1;" | |||
| id="stop7086" /> | |||
| <stop | |||
| offset="0.9375" | |||
| style="stop-color:rgb(21.090698%,20.372009%,20.797729%);stop-opacity:1;" | |||
| id="stop7088" /> | |||
| <stop | |||
| offset="0.953125" | |||
| style="stop-color:rgb(20.889282%,20.158386%,20.576477%);stop-opacity:1;" | |||
| id="stop7090" /> | |||
| <stop | |||
| offset="0.96875" | |||
| style="stop-color:rgb(20.68634%,19.944763%,20.35675%);stop-opacity:1;" | |||
| id="stop7092" /> | |||
| <stop | |||
| offset="0.984375" | |||
| style="stop-color:rgb(20.484924%,19.729614%,20.137024%);stop-opacity:1;" | |||
| id="stop7094" /> | |||
| <stop | |||
| offset="1" | |||
| style="stop-color:rgb(20.283508%,19.515991%,19.917297%);stop-opacity:1;" | |||
| id="stop7096" /> | |||
| </linearGradient> | |||
| <linearGradient | |||
| inkscape:collect="always" | |||
| xlink:href="#linearGradient1258" | |||
| id="linearGradient1260" | |||
| x1="97.483007" | |||
| y1="102.72024" | |||
| x2="112.67175" | |||
| y2="102.72024" | |||
| gradientUnits="userSpaceOnUse" | |||
| gradientTransform="rotate(90,105.07738,102.72024)" /> | |||
| </defs> | |||
| <sodipodi:namedview | |||
| id="base" | |||
| pagecolor="#ffffff" | |||
| bordercolor="#666666" | |||
| borderopacity="1.0" | |||
| inkscape:pageopacity="0.0" | |||
| inkscape:pageshadow="2" | |||
| inkscape:zoom="5.6" | |||
| inkscape:cx="27.755372" | |||
| inkscape:cy="6.7266123" | |||
| inkscape:document-units="mm" | |||
| inkscape:current-layer="layer1" | |||
| showgrid="false" | |||
| fit-margin-top="0" | |||
| fit-margin-left="0" | |||
| fit-margin-right="0" | |||
| fit-margin-bottom="0" | |||
| inkscape:window-width="1600" | |||
| inkscape:window-height="900" | |||
| inkscape:window-x="0" | |||
| inkscape:window-y="0" | |||
| inkscape:window-maximized="0" /> | |||
| <metadata | |||
| id="metadata8101"> | |||
| <rdf:RDF> | |||
| <cc:Work | |||
| rdf:about=""> | |||
| <dc:format>image/svg+xml</dc:format> | |||
| <dc:type | |||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
| <dc:title /> | |||
| </cc:Work> | |||
| </rdf:RDF> | |||
| </metadata> | |||
| <g | |||
| inkscape:label="Layer 1" | |||
| inkscape:groupmode="layer" | |||
| id="layer1" | |||
| transform="translate(-96.577641,-94.219811)"> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10029" | |||
| d="m 96.577641,102.72091 c 0,4.6936 3.804779,8.49976 8.499759,8.49976 4.69498,0 8.49972,-3.80616 8.49972,-8.49976 0,-4.69498 -3.80474,-8.501099 -8.49972,-8.501099 -4.69498,0 -8.499759,3.806119 -8.499759,8.501099" | |||
| style="fill:#050707;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path6967" | |||
| d="m 105.07671,95.125869 c -4.19336,0 -7.594391,3.399651 -7.594391,7.594391 0,4.19473 3.401031,7.59435 7.594391,7.59435 4.19474,0 7.59573,-3.39962 7.59573,-7.59435 0,-4.19474 -3.40099,-7.594391 -7.59573,-7.594391" | |||
| style="fill:url(#linearGradient1260);fill-opacity:1;stroke-width:0.35277778" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10037" | |||
| d="m 106.17016,98.225744 c 0,0.657331 -0.53192,1.189249 -1.18925,1.189249 -0.65592,0 -1.18921,-0.531918 -1.18921,-1.189249 0,-0.657331 0.53329,-1.189249 1.18921,-1.189249 0.65733,0 1.18925,0.531918 1.18925,1.189249" | |||
| style="fill:#050707;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10039" | |||
| d="m 102.83394,99.691994 c 0,0.657326 -0.53191,1.189246 -1.18925,1.189246 -0.65595,0 -1.18924,-0.53192 -1.18924,-1.189246 0,-0.655955 0.53329,-1.189249 1.18924,-1.189249 0.65734,0 1.18925,0.533294 1.18925,1.189249" | |||
| style="fill:#050707;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10041" | |||
| d="m 109.33416,99.691994 c 0,0.657326 -0.53192,1.189246 -1.18925,1.189246 -0.65733,0 -1.18925,-0.53192 -1.18925,-1.189246 0,-0.655955 0.53192,-1.189249 1.18925,-1.189249 0.65733,0 1.18925,0.533294 1.18925,1.189249" | |||
| style="fill:#050707;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10043" | |||
| d="m 110.54133,102.72641 c 0,0.65596 -0.53192,1.18925 -1.18925,1.18925 -0.65596,0 -1.18925,-0.53329 -1.18925,-1.18925 0,-0.65729 0.53329,-1.18925 1.18925,-1.18925 0.65733,0 1.18925,0.53196 1.18925,1.18925" | |||
| style="fill:#050707;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10045" | |||
| d="m 101.79903,102.72641 c 0,0.65596 -0.53191,1.18925 -1.18924,1.18925 -0.655959,0 -1.189254,-0.53329 -1.189254,-1.18925 0,-0.65729 0.533295,-1.18925 1.189254,-1.18925 0.65733,0 1.18924,0.53196 1.18924,1.18925" | |||
| style="fill:#050707;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10047" | |||
| d="m 106.54778,109.2473 h -2.94076 v 1.28294 h 2.94076 z m 0,0" | |||
| style="fill:#050707;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| </g> | |||
| </svg> | |||
| @@ -0,0 +1,376 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
| <svg | |||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
| xmlns:cc="http://creativecommons.org/ns#" | |||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
| xmlns:svg="http://www.w3.org/2000/svg" | |||
| xmlns="http://www.w3.org/2000/svg" | |||
| xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
| xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
| width="10.90027mm" | |||
| height="12.199803mm" | |||
| viewBox="0 0 10.90027 12.199803" | |||
| version="1.1" | |||
| id="svg8104" | |||
| inkscape:version="0.92.2 5c3e80d, 2017-08-06" | |||
| sodipodi:docname="USB-B.svg"> | |||
| <defs | |||
| id="defs8098"> | |||
| <clipPath | |||
| id="clip306"> | |||
| <path | |||
| d="m 1550,2365 h 44 v 44 h -44 z m 0,0" | |||
| id="path6964" | |||
| inkscape:connector-curvature="0" /> | |||
| </clipPath> | |||
| <clipPath | |||
| id="clip307"> | |||
| <path | |||
| d="m 1550.0859,2386.6914 c 0,11.8867 9.6368,21.5274 21.5274,21.5274 11.8906,0 21.5273,-9.6407 21.5273,-21.5274 0,-11.8906 -9.6367,-21.5312 -21.5273,-21.5312 -11.8906,0 -21.5274,9.6406 -21.5274,21.5312" | |||
| id="path6967" | |||
| inkscape:connector-curvature="0" /> | |||
| </clipPath> | |||
| <linearGradient | |||
| id="linear3" | |||
| gradientUnits="userSpaceOnUse" | |||
| x1="-0.0115906" | |||
| y1="0" | |||
| x2="0.985816" | |||
| y2="0" | |||
| gradientTransform="matrix(0,43.168976,-43.168976,0,1571.6138,2365.6624)"> | |||
| <stop | |||
| offset="0" | |||
| style="stop-color:rgb(32.940674%,32.940674%,33.724976%);stop-opacity:1;" | |||
| id="stop6970" /> | |||
| <stop | |||
| offset="0.03125" | |||
| style="stop-color:rgb(32.814026%,32.806396%,33.586121%);stop-opacity:1;" | |||
| id="stop6972" /> | |||
| <stop | |||
| offset="0.046875" | |||
| style="stop-color:rgb(32.58667%,32.565308%,33.338928%);stop-opacity:1;" | |||
| id="stop6974" /> | |||
| <stop | |||
| offset="0.0625" | |||
| style="stop-color:rgb(32.383728%,32.350159%,33.117676%);stop-opacity:1;" | |||
| id="stop6976" /> | |||
| <stop | |||
| offset="0.078125" | |||
| style="stop-color:rgb(32.182312%,32.136536%,32.897949%);stop-opacity:1;" | |||
| id="stop6978" /> | |||
| <stop | |||
| offset="0.09375" | |||
| style="stop-color:rgb(31.980896%,31.922913%,32.678223%);stop-opacity:1;" | |||
| id="stop6980" /> | |||
| <stop | |||
| offset="0.109375" | |||
| style="stop-color:rgb(31.77948%,31.70929%,32.458496%);stop-opacity:1;" | |||
| id="stop6982" /> | |||
| <stop | |||
| offset="0.125" | |||
| style="stop-color:rgb(31.578064%,31.495667%,32.23877%);stop-opacity:1;" | |||
| id="stop6984" /> | |||
| <stop | |||
| offset="0.140625" | |||
| style="stop-color:rgb(31.376648%,31.280518%,32.017517%);stop-opacity:1;" | |||
| id="stop6986" /> | |||
| <stop | |||
| offset="0.15625" | |||
| style="stop-color:rgb(31.173706%,31.066895%,31.797791%);stop-opacity:1;" | |||
| id="stop6988" /> | |||
| <stop | |||
| offset="0.171875" | |||
| style="stop-color:rgb(30.97229%,30.853271%,31.578064%);stop-opacity:1;" | |||
| id="stop6990" /> | |||
| <stop | |||
| offset="0.1875" | |||
| style="stop-color:rgb(30.770874%,30.639648%,31.358337%);stop-opacity:1;" | |||
| id="stop6992" /> | |||
| <stop | |||
| offset="0.203125" | |||
| style="stop-color:rgb(30.569458%,30.426025%,31.138611%);stop-opacity:1;" | |||
| id="stop6994" /> | |||
| <stop | |||
| offset="0.21875" | |||
| style="stop-color:rgb(30.368042%,30.212402%,30.917358%);stop-opacity:1;" | |||
| id="stop6996" /> | |||
| <stop | |||
| offset="0.234375" | |||
| style="stop-color:rgb(30.166626%,29.997253%,30.697632%);stop-opacity:1;" | |||
| id="stop6998" /> | |||
| <stop | |||
| offset="0.25" | |||
| style="stop-color:rgb(29.963684%,29.78363%,30.477905%);stop-opacity:1;" | |||
| id="stop7000" /> | |||
| <stop | |||
| offset="0.265625" | |||
| style="stop-color:rgb(29.762268%,29.570007%,30.258179%);stop-opacity:1;" | |||
| id="stop7002" /> | |||
| <stop | |||
| offset="0.28125" | |||
| style="stop-color:rgb(29.560852%,29.356384%,30.038452%);stop-opacity:1;" | |||
| id="stop7004" /> | |||
| <stop | |||
| offset="0.296875" | |||
| style="stop-color:rgb(29.359436%,29.142761%,29.8172%);stop-opacity:1;" | |||
| id="stop7006" /> | |||
| <stop | |||
| offset="0.3125" | |||
| style="stop-color:rgb(29.15802%,28.927612%,29.597473%);stop-opacity:1;" | |||
| id="stop7008" /> | |||
| <stop | |||
| offset="0.328125" | |||
| style="stop-color:rgb(28.955078%,28.713989%,29.377747%);stop-opacity:1;" | |||
| id="stop7010" /> | |||
| <stop | |||
| offset="0.34375" | |||
| style="stop-color:rgb(28.753662%,28.500366%,29.15802%);stop-opacity:1;" | |||
| id="stop7012" /> | |||
| <stop | |||
| offset="0.359375" | |||
| style="stop-color:rgb(28.552246%,28.286743%,28.938293%);stop-opacity:1;" | |||
| id="stop7014" /> | |||
| <stop | |||
| offset="0.375" | |||
| style="stop-color:rgb(28.35083%,28.07312%,28.718567%);stop-opacity:1;" | |||
| id="stop7016" /> | |||
| <stop | |||
| offset="0.390625" | |||
| style="stop-color:rgb(28.149414%,27.857971%,28.497314%);stop-opacity:1;" | |||
| id="stop7018" /> | |||
| <stop | |||
| offset="0.40625" | |||
| style="stop-color:rgb(27.947998%,27.644348%,28.277588%);stop-opacity:1;" | |||
| id="stop7020" /> | |||
| <stop | |||
| offset="0.421875" | |||
| style="stop-color:rgb(27.745056%,27.430725%,28.057861%);stop-opacity:1;" | |||
| id="stop7022" /> | |||
| <stop | |||
| offset="0.4375" | |||
| style="stop-color:rgb(27.54364%,27.217102%,27.838135%);stop-opacity:1;" | |||
| id="stop7024" /> | |||
| <stop | |||
| offset="0.453125" | |||
| style="stop-color:rgb(27.342224%,27.003479%,27.618408%);stop-opacity:1;" | |||
| id="stop7026" /> | |||
| <stop | |||
| offset="0.46875" | |||
| style="stop-color:rgb(27.140808%,26.789856%,27.397156%);stop-opacity:1;" | |||
| id="stop7028" /> | |||
| <stop | |||
| offset="0.484375" | |||
| style="stop-color:rgb(26.939392%,26.574707%,27.177429%);stop-opacity:1;" | |||
| id="stop7030" /> | |||
| <stop | |||
| offset="0.5" | |||
| style="stop-color:rgb(26.737976%,26.361084%,26.957703%);stop-opacity:1;" | |||
| id="stop7032" /> | |||
| <stop | |||
| offset="0.515625" | |||
| style="stop-color:rgb(26.535034%,26.147461%,26.737976%);stop-opacity:1;" | |||
| id="stop7034" /> | |||
| <stop | |||
| offset="0.53125" | |||
| style="stop-color:rgb(26.333618%,25.933838%,26.51825%);stop-opacity:1;" | |||
| id="stop7036" /> | |||
| <stop | |||
| offset="0.546875" | |||
| style="stop-color:rgb(26.132202%,25.720215%,26.296997%);stop-opacity:1;" | |||
| id="stop7038" /> | |||
| <stop | |||
| offset="0.5625" | |||
| style="stop-color:rgb(25.930786%,25.505066%,26.077271%);stop-opacity:1;" | |||
| id="stop7040" /> | |||
| <stop | |||
| offset="0.578125" | |||
| style="stop-color:rgb(25.72937%,25.291443%,25.857544%);stop-opacity:1;" | |||
| id="stop7042" /> | |||
| <stop | |||
| offset="0.59375" | |||
| style="stop-color:rgb(25.527954%,25.07782%,25.637817%);stop-opacity:1;" | |||
| id="stop7044" /> | |||
| <stop | |||
| offset="0.609375" | |||
| style="stop-color:rgb(25.325012%,24.864197%,25.418091%);stop-opacity:1;" | |||
| id="stop7046" /> | |||
| <stop | |||
| offset="0.625" | |||
| style="stop-color:rgb(25.123596%,24.650574%,25.196838%);stop-opacity:1;" | |||
| id="stop7048" /> | |||
| <stop | |||
| offset="0.640625" | |||
| style="stop-color:rgb(24.92218%,24.436951%,24.977112%);stop-opacity:1;" | |||
| id="stop7050" /> | |||
| <stop | |||
| offset="0.65625" | |||
| style="stop-color:rgb(24.720764%,24.221802%,24.757385%);stop-opacity:1;" | |||
| id="stop7052" /> | |||
| <stop | |||
| offset="0.671875" | |||
| style="stop-color:rgb(24.519348%,24.008179%,24.537659%);stop-opacity:1;" | |||
| id="stop7054" /> | |||
| <stop | |||
| offset="0.6875" | |||
| style="stop-color:rgb(24.316406%,23.794556%,24.317932%);stop-opacity:1;" | |||
| id="stop7056" /> | |||
| <stop | |||
| offset="0.703125" | |||
| style="stop-color:rgb(24.11499%,23.580933%,24.098206%);stop-opacity:1;" | |||
| id="stop7058" /> | |||
| <stop | |||
| offset="0.71875" | |||
| style="stop-color:rgb(23.913574%,23.36731%,23.876953%);stop-opacity:1;" | |||
| id="stop7060" /> | |||
| <stop | |||
| offset="0.734375" | |||
| style="stop-color:rgb(23.712158%,23.152161%,23.657227%);stop-opacity:1;" | |||
| id="stop7062" /> | |||
| <stop | |||
| offset="0.75" | |||
| style="stop-color:rgb(23.510742%,22.938538%,23.4375%);stop-opacity:1;" | |||
| id="stop7064" /> | |||
| <stop | |||
| offset="0.765625" | |||
| style="stop-color:rgb(23.309326%,22.724915%,23.217773%);stop-opacity:1;" | |||
| id="stop7066" /> | |||
| <stop | |||
| offset="0.78125" | |||
| style="stop-color:rgb(23.106384%,22.511292%,22.998047%);stop-opacity:1;" | |||
| id="stop7068" /> | |||
| <stop | |||
| offset="0.796875" | |||
| style="stop-color:rgb(22.904968%,22.297668%,22.776794%);stop-opacity:1;" | |||
| id="stop7070" /> | |||
| <stop | |||
| offset="0.8125" | |||
| style="stop-color:rgb(22.703552%,22.084045%,22.557068%);stop-opacity:1;" | |||
| id="stop7072" /> | |||
| <stop | |||
| offset="0.828125" | |||
| style="stop-color:rgb(22.502136%,21.868896%,22.337341%);stop-opacity:1;" | |||
| id="stop7074" /> | |||
| <stop | |||
| offset="0.84375" | |||
| style="stop-color:rgb(22.30072%,21.655273%,22.117615%);stop-opacity:1;" | |||
| id="stop7076" /> | |||
| <stop | |||
| offset="0.859375" | |||
| style="stop-color:rgb(22.099304%,21.44165%,21.897888%);stop-opacity:1;" | |||
| id="stop7078" /> | |||
| <stop | |||
| offset="0.875" | |||
| style="stop-color:rgb(21.896362%,21.228027%,21.676636%);stop-opacity:1;" | |||
| id="stop7080" /> | |||
| <stop | |||
| offset="0.890625" | |||
| style="stop-color:rgb(21.694946%,21.014404%,21.456909%);stop-opacity:1;" | |||
| id="stop7082" /> | |||
| <stop | |||
| offset="0.90625" | |||
| style="stop-color:rgb(21.49353%,20.799255%,21.237183%);stop-opacity:1;" | |||
| id="stop7084" /> | |||
| <stop | |||
| offset="0.921875" | |||
| style="stop-color:rgb(21.292114%,20.585632%,21.017456%);stop-opacity:1;" | |||
| id="stop7086" /> | |||
| <stop | |||
| offset="0.9375" | |||
| style="stop-color:rgb(21.090698%,20.372009%,20.797729%);stop-opacity:1;" | |||
| id="stop7088" /> | |||
| <stop | |||
| offset="0.953125" | |||
| style="stop-color:rgb(20.889282%,20.158386%,20.576477%);stop-opacity:1;" | |||
| id="stop7090" /> | |||
| <stop | |||
| offset="0.96875" | |||
| style="stop-color:rgb(20.68634%,19.944763%,20.35675%);stop-opacity:1;" | |||
| id="stop7092" /> | |||
| <stop | |||
| offset="0.984375" | |||
| style="stop-color:rgb(20.484924%,19.729614%,20.137024%);stop-opacity:1;" | |||
| id="stop7094" /> | |||
| <stop | |||
| offset="1" | |||
| style="stop-color:rgb(20.283508%,19.515991%,19.917297%);stop-opacity:1;" | |||
| id="stop7096" /> | |||
| </linearGradient> | |||
| </defs> | |||
| <sodipodi:namedview | |||
| id="base" | |||
| pagecolor="#ffffff" | |||
| bordercolor="#666666" | |||
| borderopacity="1.0" | |||
| inkscape:pageopacity="0.0" | |||
| inkscape:pageshadow="2" | |||
| inkscape:zoom="1.979899" | |||
| inkscape:cx="-53.032455" | |||
| inkscape:cy="-10.55258" | |||
| inkscape:document-units="mm" | |||
| inkscape:current-layer="layer1" | |||
| showgrid="false" | |||
| fit-margin-top="0" | |||
| fit-margin-left="0" | |||
| fit-margin-right="0" | |||
| fit-margin-bottom="0" | |||
| inkscape:window-width="1600" | |||
| inkscape:window-height="882" | |||
| inkscape:window-x="0" | |||
| inkscape:window-y="18" | |||
| inkscape:window-maximized="0" /> | |||
| <metadata | |||
| id="metadata8101"> | |||
| <rdf:RDF> | |||
| <cc:Work | |||
| rdf:about=""> | |||
| <dc:format>image/svg+xml</dc:format> | |||
| <dc:type | |||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
| <dc:title></dc:title> | |||
| </cc:Work> | |||
| </rdf:RDF> | |||
| </metadata> | |||
| <g | |||
| inkscape:label="Layer 1" | |||
| inkscape:groupmode="layer" | |||
| id="layer1" | |||
| transform="translate(-113.84542,-95.231797)"> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10059" | |||
| d="M 124.74569,107.4316 H 113.84542 V 95.231797 h 10.90027 z m 0,0" | |||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10061" | |||
| d="m 115.94967,107.08157 c -1.04733,0 -1.90444,-0.85714 -1.90444,-1.90447 v -7.68943 c 0,-1.047327 0.85711,-1.905847 1.90444,-1.905847 h 6.69036 c 1.04733,0 1.90447,0.85852 1.90447,1.905847 v 7.68943 c 0,1.04733 -0.85714,1.90447 -1.90447,1.90447 z m 0,0" | |||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10063" | |||
| d="m 123.47237,98.619028 c 0,-0.216358 -0.11712,-0.516749 -0.2577,-0.668337 l -1.16304,-1.233347 c -0.14196,-0.151588 -0.42446,-0.277001 -0.62703,-0.277001 h -5.57138 c -0.40655,0 -0.73727,0.352778 -0.73727,0.784119 v 8.215848 c 0,0.42996 0.33072,0.78412 0.73727,0.78412 h 5.57138 c 0.20257,0 0.48507,-0.12679 0.62841,-0.27838 l 1.16166,-1.23197 c 0.14058,-0.15155 0.2577,-0.45336 0.2577,-0.66971 z m 0,0" | |||
| style="fill:#cccaca;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10065" | |||
| d="m 121.75946,104.99383 h -4.69357 v -7.164424 h 4.69357 z m 0,0" | |||
| style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#a1a3a1;stroke-width:0.08819444;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-opacity:1" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10067" | |||
| d="m 120.60193,103.78529 h -2.53284 v -4.745963 h 2.53284 z m 0,0" | |||
| style="fill:#424242;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10069" | |||
| d="m 120.84309,99.71458 h -0.37483 v 1.10243 h 0.37483 z m 0,0" | |||
| style="fill:#e1ba21;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| <path | |||
| inkscape:connector-curvature="0" | |||
| id="path10071" | |||
| d="m 120.84309,102.00764 h -0.37483 v 1.10243 h 0.37483 z m 0,0" | |||
| style="fill:#e1ba21;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
| </g> | |||
| </svg> | |||
| @@ -0,0 +1,115 @@ | |||
| #include "app.hpp" | |||
| #include "audio.hpp" | |||
| namespace rack { | |||
| struct AudioDriverItem : MenuItem { | |||
| AudioIO *audioIO; | |||
| int driver; | |||
| void onAction(EventAction &e) override { | |||
| audioIO->setDriver(driver); | |||
| } | |||
| }; | |||
| struct AudioDeviceItem : MenuItem { | |||
| AudioIO *audioIO; | |||
| int device; | |||
| void onAction(EventAction &e) override { | |||
| audioIO->device = device; | |||
| audioIO->openStream(); | |||
| } | |||
| }; | |||
| struct AudioSampleRateItem : MenuItem { | |||
| AudioIO *audioIO; | |||
| int sampleRate; | |||
| void onAction(EventAction &e) override { | |||
| audioIO->sampleRate = sampleRate; | |||
| audioIO->openStream(); | |||
| } | |||
| }; | |||
| struct AudioBlockSizeItem : MenuItem { | |||
| AudioIO *audioIO; | |||
| int blockSize; | |||
| void onAction(EventAction &e) override { | |||
| audioIO->blockSize = blockSize; | |||
| audioIO->openStream(); | |||
| } | |||
| }; | |||
| void AudioWidget::onMouseDown(EventMouseDown &e) { | |||
| OpaqueWidget::onMouseDown(e); | |||
| if (!audioIO) | |||
| return; | |||
| Menu *menu = gScene->createMenu(); | |||
| // Audio driver | |||
| menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Audio driver")); | |||
| for (int driver : audioIO->listDrivers()) { | |||
| AudioDriverItem *item = new AudioDriverItem(); | |||
| item->audioIO = audioIO; | |||
| item->driver = driver; | |||
| item->text = audioIO->getDriverName(driver); | |||
| item->rightText = CHECKMARK(item->driver == audioIO->getDriver()); | |||
| menu->addChild(item); | |||
| } | |||
| menu->addChild(construct<MenuEntry>()); | |||
| // Audio device | |||
| menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Audio device")); | |||
| int deviceCount = audioIO->getDeviceCount(); | |||
| { | |||
| AudioDeviceItem *item = new AudioDeviceItem(); | |||
| item->audioIO = audioIO; | |||
| item->device = -1; | |||
| item->text = "No device"; | |||
| item->rightText = CHECKMARK(item->device == audioIO->device); | |||
| menu->addChild(item); | |||
| } | |||
| for (int device = 0; device < deviceCount; device++) { | |||
| AudioDeviceItem *item = new AudioDeviceItem(); | |||
| item->audioIO = audioIO; | |||
| item->device = device; | |||
| item->text = audioIO->getDeviceDetail(device); | |||
| item->rightText = CHECKMARK(item->device == audioIO->device); | |||
| menu->addChild(item); | |||
| } | |||
| menu->addChild(construct<MenuEntry>()); | |||
| // Sample rate | |||
| menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Sample rate")); | |||
| for (int sampleRate : audioIO->listSampleRates()) { | |||
| AudioSampleRateItem *item = new AudioSampleRateItem(); | |||
| item->audioIO = audioIO; | |||
| item->sampleRate = sampleRate; | |||
| item->text = stringf("%d Hz", sampleRate); | |||
| item->rightText = CHECKMARK(item->sampleRate == audioIO->sampleRate); | |||
| menu->addChild(item); | |||
| } | |||
| menu->addChild(construct<MenuEntry>()); | |||
| // Block size | |||
| menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Block size")); | |||
| std::vector<int> blockSizes = {64, 128, 256, 512, 1024, 2048, 4096}; | |||
| for (int blockSize : blockSizes) { | |||
| AudioBlockSizeItem *item = new AudioBlockSizeItem(); | |||
| item->audioIO = audioIO; | |||
| item->blockSize = blockSize; | |||
| float latency = (float) blockSize / audioIO->sampleRate * 1000.0; | |||
| item->text = stringf("%d (%.1f ms)", blockSize, latency); | |||
| item->rightText = CHECKMARK(item->blockSize == audioIO->blockSize); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| } // namespace rack | |||
| @@ -1,7 +1,7 @@ | |||
| #include "app.hpp" | |||
| #include "gui.hpp" | |||
| #include "components.hpp" | |||
| #include "engine.hpp" | |||
| #include "componentlibrary.hpp" | |||
| namespace rack { | |||
| @@ -53,13 +53,13 @@ struct FileChoice : ChoiceButton { | |||
| }; | |||
| struct PauseItem : MenuItem { | |||
| struct EnginePauseItem : MenuItem { | |||
| void onAction(EventAction &e) override { | |||
| gPaused = !gPaused; | |||
| } | |||
| }; | |||
| struct SampleRateItem : MenuItem { | |||
| struct EngineSampleRateItem : MenuItem { | |||
| float sampleRate; | |||
| void onAction(EventAction &e) override { | |||
| engineSetSampleRate(sampleRate); | |||
| @@ -67,22 +67,21 @@ struct SampleRateItem : MenuItem { | |||
| } | |||
| }; | |||
| struct SampleRateChoice : ChoiceButton { | |||
| struct EngineSampleRateChoice : ChoiceButton { | |||
| void onAction(EventAction &e) override { | |||
| Menu *menu = gScene->createMenu(); | |||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); | |||
| menu->box.size.x = box.size.x; | |||
| PauseItem *pauseItem = new PauseItem(); | |||
| EnginePauseItem *pauseItem = new EnginePauseItem(); | |||
| pauseItem->text = gPaused ? "Resume engine" : "Pause engine"; | |||
| menu->addChild(pauseItem); | |||
| float sampleRates[] = {44100, 48000, 88200, 96000, 176400, 192000}; | |||
| int sampleRatesLen = sizeof(sampleRates) / sizeof(sampleRates[0]); | |||
| for (int i = 0; i < sampleRatesLen; i++) { | |||
| SampleRateItem *item = new SampleRateItem(); | |||
| item->text = stringf("%.0f Hz", sampleRates[i]); | |||
| item->sampleRate = sampleRates[i]; | |||
| std::vector<float> sampleRates = {44100, 48000, 88200, 96000, 176400, 192000}; | |||
| for (float sampleRate : sampleRates) { | |||
| EngineSampleRateItem *item = new EngineSampleRateItem(); | |||
| item->text = stringf("%.0f Hz", sampleRate); | |||
| item->sampleRate = sampleRate; | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| @@ -112,7 +111,7 @@ Toolbar::Toolbar() { | |||
| xPos += margin; | |||
| { | |||
| SampleRateChoice *srChoice = new SampleRateChoice(); | |||
| EngineSampleRateChoice *srChoice = new EngineSampleRateChoice(); | |||
| srChoice->box.pos = Vec(xPos, margin); | |||
| srChoice->box.size.x = 100; | |||
| addChild(srChoice); | |||
| @@ -1,6 +1,6 @@ | |||
| #include "app.hpp" | |||
| #include "engine.hpp" | |||
| #include "components.hpp" | |||
| #include "componentlibrary.hpp" | |||
| #include "gui.hpp" | |||
| @@ -0,0 +1,212 @@ | |||
| #include "util.hpp" | |||
| #include "math.hpp" | |||
| #include "audio.hpp" | |||
| namespace rack { | |||
| AudioIO::AudioIO() { | |||
| setDriver(RtAudio::UNSPECIFIED); | |||
| } | |||
| AudioIO::~AudioIO() { | |||
| closeStream(); | |||
| } | |||
| std::vector<int> AudioIO::listDrivers() { | |||
| std::vector<RtAudio::Api> apis; | |||
| RtAudio::getCompiledApi(apis); | |||
| std::vector<int> drivers; | |||
| for (RtAudio::Api api : apis) | |||
| drivers.push_back((int) api); | |||
| return drivers; | |||
| } | |||
| std::string AudioIO::getDriverName(int driver) { | |||
| switch (driver) { | |||
| case RtAudio::UNSPECIFIED: return "Unspecified"; | |||
| case RtAudio::LINUX_ALSA: return "ALSA"; | |||
| case RtAudio::LINUX_PULSE: return "PulseAudio"; | |||
| case RtAudio::LINUX_OSS: return "OSS"; | |||
| case RtAudio::UNIX_JACK: return "JACK"; | |||
| case RtAudio::MACOSX_CORE: return "Core Audio"; | |||
| case RtAudio::WINDOWS_WASAPI: return "WASAPI"; | |||
| case RtAudio::WINDOWS_ASIO: return "ASIO"; | |||
| case RtAudio::WINDOWS_DS: return "DirectSound"; | |||
| case RtAudio::RTAUDIO_DUMMY: return "Dummy"; | |||
| default: return "Unknown"; | |||
| } | |||
| } | |||
| int AudioIO::getDriver() { | |||
| if (!stream) | |||
| return RtAudio::UNSPECIFIED; | |||
| return stream->getCurrentApi(); | |||
| } | |||
| void AudioIO::setDriver(int driver) { | |||
| // closeStream(); | |||
| if (stream) | |||
| delete stream; | |||
| stream = new RtAudio((RtAudio::Api) driver); | |||
| } | |||
| int AudioIO::getDeviceCount() { | |||
| if (!stream) | |||
| return 0; | |||
| return stream->getDeviceCount(); | |||
| } | |||
| std::string AudioIO::getDeviceName(int device) { | |||
| if (!stream || device < 0) | |||
| return ""; | |||
| try { | |||
| RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device); | |||
| return deviceInfo.name; | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to query audio device: %s", e.what()); | |||
| return ""; | |||
| } | |||
| } | |||
| std::string AudioIO::getDeviceDetail(int device) { | |||
| if (!stream || device < 0) | |||
| return ""; | |||
| try { | |||
| RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device); | |||
| return stringf("%s (%d in, %d out)", deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to query audio device: %s", e.what()); | |||
| return ""; | |||
| } | |||
| } | |||
| static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) { | |||
| AudioIO *audioIO = (AudioIO*) userData; | |||
| assert(audioIO); | |||
| // audioInterface->stepStream((const float *) inputBuffer, (float *) outputBuffer, nFrames); | |||
| return 0; | |||
| } | |||
| void AudioIO::openStream() { | |||
| // Close device but remember the current device number | |||
| int device = this->device; | |||
| closeStream(); | |||
| if (!stream) | |||
| return; | |||
| // Open new device | |||
| if (device >= 0) { | |||
| RtAudio::DeviceInfo deviceInfo; | |||
| try { | |||
| deviceInfo = stream->getDeviceInfo(device); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to query audio device: %s", e.what()); | |||
| return; | |||
| } | |||
| numOutputs = mini(deviceInfo.outputChannels, maxOutputs); | |||
| numInputs = mini(deviceInfo.inputChannels, maxInputs); | |||
| if (numOutputs == 0 && numInputs == 0) { | |||
| warn("Audio device %d has 0 inputs and 0 outputs"); | |||
| return; | |||
| } | |||
| RtAudio::StreamParameters outParameters; | |||
| outParameters.deviceId = device; | |||
| outParameters.nChannels = numOutputs; | |||
| RtAudio::StreamParameters inParameters; | |||
| inParameters.deviceId = device; | |||
| inParameters.nChannels = numInputs; | |||
| RtAudio::StreamOptions options; | |||
| // options.flags |= RTAUDIO_SCHEDULE_REALTIME; | |||
| // Find closest sample rate | |||
| unsigned int closestSampleRate = 0; | |||
| for (unsigned int sr : deviceInfo.sampleRates) { | |||
| if (fabsf(sr - sampleRate) < fabsf(closestSampleRate - sampleRate)) { | |||
| closestSampleRate = sr; | |||
| } | |||
| } | |||
| try { | |||
| debug("Opening audio stream %d", device); | |||
| stream->openStream( | |||
| numOutputs == 0 ? NULL : &outParameters, | |||
| numInputs == 0 ? NULL : &inParameters, | |||
| RTAUDIO_FLOAT32, closestSampleRate, (unsigned int*) &blockSize, &rtCallback, this, &options, NULL); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to open audio stream: %s", e.what()); | |||
| return; | |||
| } | |||
| try { | |||
| debug("Starting audio stream %d", device); | |||
| stream->startStream(); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to start audio stream: %s", e.what()); | |||
| return; | |||
| } | |||
| // Update sample rate because this may have changed | |||
| this->sampleRate = stream->getStreamSampleRate(); | |||
| this->device = device; | |||
| } | |||
| } | |||
| void AudioIO::closeStream() { | |||
| if (stream) { | |||
| if (stream->isStreamRunning()) { | |||
| debug("Aborting audio stream %d", device); | |||
| try { | |||
| stream->abortStream(); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to abort stream %s", e.what()); | |||
| } | |||
| } | |||
| if (stream->isStreamOpen()) { | |||
| debug("Closing audio stream %d", device); | |||
| try { | |||
| stream->closeStream(); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to close stream %s", e.what()); | |||
| } | |||
| } | |||
| } | |||
| // Reset stream settings | |||
| device = -1; | |||
| numOutputs = 0; | |||
| numInputs = 0; | |||
| } | |||
| std::vector<int> AudioIO::listSampleRates() { | |||
| if (!stream || device < 0) | |||
| return {}; | |||
| try { | |||
| RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device); | |||
| std::vector<int> sampleRates(deviceInfo.sampleRates.begin(), deviceInfo.sampleRates.end()); | |||
| return sampleRates; | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to query audio device: %s", e.what()); | |||
| return {}; | |||
| } | |||
| } | |||
| } // namespace rack | |||
| @@ -1,8 +1,8 @@ | |||
| #include <assert.h> | |||
| #include <mutex> | |||
| #include <thread> | |||
| #include <algorithm> | |||
| #include "core.hpp" | |||
| #include "audio.hpp" | |||
| #include "dsp/samplerate.hpp" | |||
| #include "dsp/ringbuffer.hpp" | |||
| @@ -29,13 +29,7 @@ struct AudioInterface : Module { | |||
| NUM_OUTPUTS = AUDIO1_OUTPUT + 8 | |||
| }; | |||
| RtAudio *stream = NULL; | |||
| // Stream properties | |||
| int device = -1; | |||
| float sampleRate = 44100.0; | |||
| int blockSize = 256; | |||
| int numOutputs = 0; | |||
| int numInputs = 0; | |||
| AudioIO audioIO; | |||
| SampleRateConverter<8> inputSrc; | |||
| SampleRateConverter<8> outputSrc; | |||
| @@ -47,89 +41,43 @@ struct AudioInterface : Module { | |||
| DoubleRingBuffer<Frame<8>, (1<<15)> inputSrcBuffer; | |||
| AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | |||
| setDriver(RtAudio::UNSPECIFIED); | |||
| } | |||
| ~AudioInterface() { | |||
| closeStream(); | |||
| } | |||
| void step() override; | |||
| void stepStream(const float *input, float *output, int numFrames); | |||
| int getDeviceCount(); | |||
| std::string getDeviceName(int device); | |||
| void openStream(); | |||
| void closeStream(); | |||
| void setDriver(int driver) { | |||
| closeStream(); | |||
| if (stream) | |||
| delete stream; | |||
| stream = new RtAudio((RtAudio::Api) driver); | |||
| } | |||
| int getDriver() { | |||
| if (!stream) | |||
| return RtAudio::UNSPECIFIED; | |||
| return stream->getCurrentApi(); | |||
| } | |||
| std::vector<int> getAvailableDrivers() { | |||
| std::vector<RtAudio::Api> apis; | |||
| RtAudio::getCompiledApi(apis); | |||
| std::vector<int> drivers; | |||
| for (RtAudio::Api api : apis) | |||
| drivers.push_back(api); | |||
| return drivers; | |||
| } | |||
| std::string getDriverName(int driver) { | |||
| switch (driver) { | |||
| case RtAudio::UNSPECIFIED: return "Unspecified"; | |||
| case RtAudio::LINUX_ALSA: return "ALSA"; | |||
| case RtAudio::LINUX_PULSE: return "PulseAudio"; | |||
| case RtAudio::LINUX_OSS: return "OSS"; | |||
| case RtAudio::UNIX_JACK: return "JACK"; | |||
| case RtAudio::MACOSX_CORE: return "Core Audio"; | |||
| case RtAudio::WINDOWS_WASAPI: return "WASAPI"; | |||
| case RtAudio::WINDOWS_ASIO: return "ASIO"; | |||
| case RtAudio::WINDOWS_DS: return "DirectSound"; | |||
| case RtAudio::RTAUDIO_DUMMY: return "Dummy"; | |||
| default: return "Unknown"; | |||
| } | |||
| } | |||
| std::vector<float> getSampleRates(); | |||
| json_t *toJson() override { | |||
| json_t *rootJ = json_object(); | |||
| json_object_set_new(rootJ, "driver", json_integer(getDriver())); | |||
| json_object_set_new(rootJ, "device", json_integer(device)); | |||
| json_object_set_new(rootJ, "sampleRate", json_real(sampleRate)); | |||
| json_object_set_new(rootJ, "blockSize", json_integer(blockSize)); | |||
| // json_object_set_new(rootJ, "driver", json_integer(getDriver())); | |||
| // json_object_set_new(rootJ, "device", json_integer(device)); | |||
| // json_object_set_new(rootJ, "audioIO.sampleRate", json_real(audioIO.sampleRate)); | |||
| // json_object_set_new(rootJ, "audioIO.blockSize", json_integer(audioIO.blockSize)); | |||
| return rootJ; | |||
| } | |||
| void fromJson(json_t *rootJ) override { | |||
| json_t *driverJ = json_object_get(rootJ, "driver"); | |||
| if (driverJ) | |||
| setDriver(json_number_value(driverJ)); | |||
| // json_t *driverJ = json_object_get(rootJ, "driver"); | |||
| // if (driverJ) | |||
| // setDriver(json_number_value(driverJ)); | |||
| json_t *deviceJ = json_object_get(rootJ, "device"); | |||
| if (deviceJ) | |||
| device = json_number_value(deviceJ); | |||
| // json_t *deviceJ = json_object_get(rootJ, "device"); | |||
| // if (deviceJ) | |||
| // device = json_number_value(deviceJ); | |||
| json_t *sampleRateJ = json_object_get(rootJ, "sampleRate"); | |||
| if (sampleRateJ) | |||
| sampleRate = json_number_value(sampleRateJ); | |||
| // json_t *sampleRateJ = json_object_get(rootJ, "audioIO.sampleRate"); | |||
| // if (sampleRateJ) | |||
| // audioIO.sampleRate = json_number_value(sampleRateJ); | |||
| json_t *blockSizeJ = json_object_get(rootJ, "blockSize"); | |||
| if (blockSizeJ) | |||
| blockSize = json_integer_value(blockSizeJ); | |||
| // json_t *blockSizeJ = json_object_get(rootJ, "audioIO.blockSize"); | |||
| // if (blockSizeJ) | |||
| // audioIO.blockSize = json_integer_value(blockSizeJ); | |||
| openStream(); | |||
| // openStream(); | |||
| } | |||
| void onReset() override { | |||
| closeStream(); | |||
| audioIO.closeStream(); | |||
| } | |||
| }; | |||
| @@ -149,15 +97,15 @@ struct AudioInterface : Module { | |||
| void AudioInterface::step() { | |||
| // debug("inputBuffer %d inputSrcBuffer %d outputBuffer %d", inputBuffer.size(), inputSrcBuffer.size(), outputBuffer.size()); | |||
| // Read/write stream if we have enough input, OR the output buffer is empty if we have no input | |||
| if (numOutputs > 0) { | |||
| TIMED_SLEEP_LOCK(inputSrcBuffer.size() < blockSize, 100e-6, 0.2); | |||
| if (audioIO.numOutputs > 0) { | |||
| TIMED_SLEEP_LOCK(inputSrcBuffer.size() < audioIO.blockSize, 100e-6, 0.2); | |||
| } | |||
| else if (numInputs > 0) { | |||
| else if (audioIO.numInputs > 0) { | |||
| TIMED_SLEEP_LOCK(!outputBuffer.empty(), 100e-6, 0.2); | |||
| } | |||
| // Get input and pass it through the sample rate converter | |||
| if (numOutputs > 0) { | |||
| if (audioIO.numOutputs > 0) { | |||
| if (!inputBuffer.full()) { | |||
| Frame<8> f; | |||
| for (int i = 0; i < 8; i++) { | |||
| @@ -169,7 +117,7 @@ void AudioInterface::step() { | |||
| // Once full, sample rate convert the input | |||
| // inputBuffer -> SRC -> inputSrcBuffer | |||
| if (inputBuffer.full()) { | |||
| inputSrc.setRates(engineGetSampleRate(), sampleRate); | |||
| inputSrc.setRates(engineGetSampleRate(), audioIO.sampleRate); | |||
| int inLen = inputBuffer.size(); | |||
| int outLen = inputSrcBuffer.capacity(); | |||
| inputSrc.process(inputBuffer.startData(), &inLen, inputSrcBuffer.endData(), &outLen); | |||
| @@ -189,29 +137,29 @@ void AudioInterface::step() { | |||
| void AudioInterface::stepStream(const float *input, float *output, int numFrames) { | |||
| if (gPaused) { | |||
| memset(output, 0, sizeof(float) * numOutputs * numFrames); | |||
| memset(output, 0, sizeof(float) * audioIO.numOutputs * numFrames); | |||
| return; | |||
| } | |||
| if (numOutputs > 0) { | |||
| if (audioIO.numOutputs > 0) { | |||
| // Wait for enough input before proceeding | |||
| TIMED_SLEEP_LOCK(inputSrcBuffer.size() >= numFrames, 100e-6, 0.2); | |||
| } | |||
| else if (numInputs > 0) { | |||
| else if (audioIO.numInputs > 0) { | |||
| TIMED_SLEEP_LOCK(outputBuffer.empty(), 100e-6, 0.2); | |||
| } | |||
| // input stream -> output buffer | |||
| if (numInputs > 0) { | |||
| if (audioIO.numInputs > 0) { | |||
| Frame<8> inputFrames[numFrames]; | |||
| for (int i = 0; i < numFrames; i++) { | |||
| for (int c = 0; c < 8; c++) { | |||
| inputFrames[i].samples[c] = (c < numInputs) ? input[i*numInputs + c] : 0.0; | |||
| inputFrames[i].samples[c] = (c < audioIO.numInputs) ? input[i*audioIO.numInputs + c] : 0.0; | |||
| } | |||
| } | |||
| // Pass output through sample rate converter | |||
| outputSrc.setRates(sampleRate, engineGetSampleRate()); | |||
| outputSrc.setRates(audioIO.sampleRate, engineGetSampleRate()); | |||
| int inLen = numFrames; | |||
| int outLen = outputBuffer.capacity(); | |||
| outputSrc.process(inputFrames, &inLen, outputBuffer.endData(), &outLen); | |||
| @@ -219,7 +167,7 @@ void AudioInterface::stepStream(const float *input, float *output, int numFrames | |||
| } | |||
| // input buffer -> output stream | |||
| if (numOutputs > 0) { | |||
| if (audioIO.numOutputs > 0) { | |||
| for (int i = 0; i < numFrames; i++) { | |||
| Frame<8> f; | |||
| if (inputSrcBuffer.empty()) { | |||
| @@ -228,304 +176,23 @@ void AudioInterface::stepStream(const float *input, float *output, int numFrames | |||
| else { | |||
| f = inputSrcBuffer.shift(); | |||
| } | |||
| for (int c = 0; c < numOutputs; c++) { | |||
| output[i*numOutputs + c] = clampf(f.samples[c], -1.0, 1.0); | |||
| for (int c = 0; c < audioIO.numOutputs; c++) { | |||
| output[i*audioIO.numOutputs + c] = clampf(f.samples[c], -1.0, 1.0); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| int AudioInterface::getDeviceCount() { | |||
| if (!stream) | |||
| return 0; | |||
| return stream->getDeviceCount(); | |||
| } | |||
| std::string AudioInterface::getDeviceName(int device) { | |||
| if (!stream || device < 0) | |||
| return ""; | |||
| try { | |||
| RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device); | |||
| return stringf("%s (%d in, %d out)", deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to query audio device: %s", e.what()); | |||
| return ""; | |||
| } | |||
| } | |||
| static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) { | |||
| AudioInterface *audioInterface = (AudioInterface *) userData; | |||
| assert(audioInterface); | |||
| audioInterface->stepStream((const float *) inputBuffer, (float *) outputBuffer, nFrames); | |||
| return 0; | |||
| } | |||
| void AudioInterface::openStream() { | |||
| int device = this->device; | |||
| closeStream(); | |||
| if (!stream) | |||
| return; | |||
| // Open new device | |||
| if (device >= 0) { | |||
| RtAudio::DeviceInfo deviceInfo; | |||
| try { | |||
| deviceInfo = stream->getDeviceInfo(device); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to query audio device: %s", e.what()); | |||
| return; | |||
| } | |||
| numOutputs = mini(deviceInfo.outputChannels, 8); | |||
| numInputs = mini(deviceInfo.inputChannels, 8); | |||
| if (numOutputs == 0 && numInputs == 0) { | |||
| warn("Audio device %d has 0 inputs and 0 outputs"); | |||
| return; | |||
| } | |||
| RtAudio::StreamParameters outParameters; | |||
| outParameters.deviceId = device; | |||
| outParameters.nChannels = numOutputs; | |||
| RtAudio::StreamParameters inParameters; | |||
| inParameters.deviceId = device; | |||
| inParameters.nChannels = numInputs; | |||
| RtAudio::StreamOptions options; | |||
| // options.flags |= RTAUDIO_SCHEDULE_REALTIME; | |||
| // Find closest sample rate | |||
| unsigned int closestSampleRate = 0; | |||
| for (unsigned int sr : deviceInfo.sampleRates) { | |||
| if (fabsf(sr - sampleRate) < fabsf(closestSampleRate - sampleRate)) { | |||
| closestSampleRate = sr; | |||
| } | |||
| } | |||
| try { | |||
| // Don't use stream parameters if 0 input or output channels | |||
| debug("Opening audio stream %d", device); | |||
| stream->openStream( | |||
| numOutputs == 0 ? NULL : &outParameters, | |||
| numInputs == 0 ? NULL : &inParameters, | |||
| RTAUDIO_FLOAT32, closestSampleRate, (unsigned int*) &blockSize, &rtCallback, this, &options, NULL); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to open audio stream: %s", e.what()); | |||
| return; | |||
| } | |||
| try { | |||
| debug("Starting audio stream %d", device); | |||
| stream->startStream(); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to start audio stream: %s", e.what()); | |||
| return; | |||
| } | |||
| // Update sample rate because this may have changed | |||
| this->sampleRate = stream->getStreamSampleRate(); | |||
| this->device = device; | |||
| } | |||
| } | |||
| void AudioInterface::closeStream() { | |||
| if (stream) { | |||
| if (stream->isStreamRunning()) { | |||
| debug("Aborting audio stream %d", device); | |||
| try { | |||
| stream->abortStream(); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to abort stream %s", e.what()); | |||
| } | |||
| } | |||
| if (stream->isStreamOpen()) { | |||
| debug("Closing audio stream %d", device); | |||
| try { | |||
| stream->closeStream(); | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to close stream %s", e.what()); | |||
| } | |||
| } | |||
| } | |||
| // Reset stream settings | |||
| device = -1; | |||
| numOutputs = 0; | |||
| numInputs = 0; | |||
| // Clear buffers | |||
| inputBuffer.clear(); | |||
| outputBuffer.clear(); | |||
| inputSrcBuffer.clear(); | |||
| inputSrc.reset(); | |||
| outputSrc.reset(); | |||
| } | |||
| std::vector<float> AudioInterface::getSampleRates() { | |||
| std::vector<float> allowedSampleRates = {44100, 48000, 88200, 96000, 176400, 192000}; | |||
| if (!stream || device < 0) | |||
| return allowedSampleRates; | |||
| try { | |||
| std::vector<float> sampleRates; | |||
| RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device); | |||
| for (int sr : deviceInfo.sampleRates) { | |||
| float sampleRate = sr; | |||
| auto allowedIt = std::find(allowedSampleRates.begin(), allowedSampleRates.end(), sampleRate); | |||
| if (allowedIt != allowedSampleRates.end()) { | |||
| sampleRates.push_back(sampleRate); | |||
| } | |||
| } | |||
| return sampleRates; | |||
| } | |||
| catch (RtAudioError &e) { | |||
| warn("Failed to query audio device: %s", e.what()); | |||
| return {}; | |||
| } | |||
| } | |||
| struct AudioDriverItem : MenuItem { | |||
| AudioInterface *audioInterface; | |||
| int driver; | |||
| void onAction(EventAction &e) override { | |||
| audioInterface->setDriver(driver); | |||
| } | |||
| }; | |||
| struct AudioDriverChoice : ChoiceButton { | |||
| AudioInterface *audioInterface; | |||
| void onAction(EventAction &e) override { | |||
| Menu *menu = gScene->createMenu(); | |||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | |||
| menu->box.size.x = box.size.x; | |||
| for (int driver : audioInterface->getAvailableDrivers()) { | |||
| AudioDriverItem *audioItem = new AudioDriverItem(); | |||
| audioItem->audioInterface = audioInterface; | |||
| audioItem->driver = driver; | |||
| audioItem->text = audioInterface->getDriverName(driver); | |||
| menu->addChild(audioItem); | |||
| } | |||
| } | |||
| void step() override { | |||
| text = audioInterface->getDriverName(audioInterface->getDriver()); | |||
| } | |||
| }; | |||
| struct AudioDeviceItem : MenuItem { | |||
| AudioInterface *audioInterface; | |||
| int device; | |||
| void onAction(EventAction &e) override { | |||
| audioInterface->device = device; | |||
| audioInterface->openStream(); | |||
| } | |||
| }; | |||
| struct AudioDeviceChoice : ChoiceButton { | |||
| int lastDeviceId = -1; | |||
| AudioInterface *audioInterface; | |||
| void onAction(EventAction &e) override { | |||
| Menu *menu = gScene->createMenu(); | |||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | |||
| menu->box.size.x = box.size.x; | |||
| int deviceCount = audioInterface->getDeviceCount(); | |||
| { | |||
| AudioDeviceItem *audioItem = new AudioDeviceItem(); | |||
| audioItem->audioInterface = audioInterface; | |||
| audioItem->device = -1; | |||
| audioItem->text = "No device"; | |||
| menu->addChild(audioItem); | |||
| } | |||
| for (int device = 0; device < deviceCount; device++) { | |||
| AudioDeviceItem *audioItem = new AudioDeviceItem(); | |||
| audioItem->audioInterface = audioInterface; | |||
| audioItem->device = device; | |||
| audioItem->text = audioInterface->getDeviceName(device); | |||
| menu->addChild(audioItem); | |||
| } | |||
| } | |||
| void step() override { | |||
| if (lastDeviceId != audioInterface->device) { | |||
| std::string name = audioInterface->getDeviceName(audioInterface->device); | |||
| text = ellipsize(name, 24); | |||
| lastDeviceId = audioInterface->device; | |||
| } | |||
| } | |||
| }; | |||
| struct SampleRateItem : MenuItem { | |||
| AudioInterface *audioInterface; | |||
| float sampleRate; | |||
| void onAction(EventAction &e) override { | |||
| audioInterface->sampleRate = sampleRate; | |||
| audioInterface->openStream(); | |||
| } | |||
| }; | |||
| struct SampleRateChoice : ChoiceButton { | |||
| AudioInterface *audioInterface; | |||
| void onAction(EventAction &e) override { | |||
| Menu *menu = gScene->createMenu(); | |||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | |||
| menu->box.size.x = box.size.x; | |||
| for (float sampleRate : audioInterface->getSampleRates()) { | |||
| SampleRateItem *item = new SampleRateItem(); | |||
| item->audioInterface = audioInterface; | |||
| item->sampleRate = sampleRate; | |||
| item->text = stringf("%.0f Hz", sampleRate); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| void step() override { | |||
| this->text = stringf("%.0f Hz", audioInterface->sampleRate); | |||
| } | |||
| }; | |||
| struct BlockSizeItem : MenuItem { | |||
| AudioInterface *audioInterface; | |||
| int blockSize; | |||
| void onAction(EventAction &e) override { | |||
| audioInterface->blockSize = blockSize; | |||
| audioInterface->openStream(); | |||
| } | |||
| }; | |||
| // void AudioInterface::closeStream() { | |||
| // // Clear buffers | |||
| // inputBuffer.clear(); | |||
| // outputBuffer.clear(); | |||
| // inputSrcBuffer.clear(); | |||
| // inputSrc.reset(); | |||
| // outputSrc.reset(); | |||
| // } | |||
| struct BlockSizeChoice : ChoiceButton { | |||
| AudioInterface *audioInterface; | |||
| void onAction(EventAction &e) override { | |||
| Menu *menu = gScene->createMenu(); | |||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | |||
| menu->box.size.x = box.size.x; | |||
| const int blockSizes[] = {64, 128, 256, 512, 1024, 2048, 4096}; | |||
| int blockSizesLen = sizeof(blockSizes) / sizeof(blockSizes[0]); | |||
| for (int i = 0; i < blockSizesLen; i++) { | |||
| BlockSizeItem *item = new BlockSizeItem(); | |||
| item->audioInterface = audioInterface; | |||
| item->blockSize = blockSizes[i]; | |||
| item->text = stringf("%d", blockSizes[i]); | |||
| menu->addChild(item); | |||
| } | |||
| } | |||
| void step() override { | |||
| this->text = stringf("%d", audioInterface->blockSize); | |||
| } | |||
| }; | |||
| AudioInterfaceWidget::AudioInterfaceWidget() { | |||
| @@ -545,69 +212,9 @@ AudioInterfaceWidget::AudioInterfaceWidget() { | |||
| Vec margin = Vec(5, 2); | |||
| float labelHeight = 15; | |||
| float yPos = margin.y; | |||
| float yPos = margin.y + 100; | |||
| float xPos; | |||
| { | |||
| Label *label = new Label(); | |||
| label->box.pos = Vec(margin.x, yPos); | |||
| label->text = "Audio driver"; | |||
| addChild(label); | |||
| yPos += labelHeight + margin.y; | |||
| AudioDriverChoice *choice = new AudioDriverChoice(); | |||
| choice->audioInterface = module; | |||
| choice->box.pos = Vec(margin.x, yPos); | |||
| choice->box.size.x = box.size.x - 2*margin.x; | |||
| addChild(choice); | |||
| yPos += choice->box.size.y + margin.y; | |||
| } | |||
| { | |||
| Label *label = new Label(); | |||
| label->box.pos = Vec(margin.x, yPos); | |||
| label->text = "Audio device"; | |||
| addChild(label); | |||
| yPos += labelHeight + margin.y; | |||
| AudioDeviceChoice *choice = new AudioDeviceChoice(); | |||
| choice->audioInterface = module; | |||
| choice->box.pos = Vec(margin.x, yPos); | |||
| choice->box.size.x = box.size.x - 2*margin.x; | |||
| addChild(choice); | |||
| yPos += choice->box.size.y + margin.y; | |||
| } | |||
| { | |||
| Label *label = new Label(); | |||
| label->box.pos = Vec(margin.x, yPos); | |||
| label->text = "Sample rate"; | |||
| addChild(label); | |||
| yPos += labelHeight + margin.y; | |||
| SampleRateChoice *choice = new SampleRateChoice(); | |||
| choice->audioInterface = module; | |||
| choice->box.pos = Vec(margin.x, yPos); | |||
| choice->box.size.x = box.size.x - 2*margin.x; | |||
| addChild(choice); | |||
| yPos += choice->box.size.y + margin.y; | |||
| } | |||
| { | |||
| Label *label = new Label(); | |||
| label->box.pos = Vec(margin.x, yPos); | |||
| label->text = "Block size"; | |||
| addChild(label); | |||
| yPos += labelHeight + margin.y; | |||
| BlockSizeChoice *choice = new BlockSizeChoice(); | |||
| choice->audioInterface = module; | |||
| choice->box.pos = Vec(margin.x, yPos); | |||
| choice->box.size.x = box.size.x - 2*margin.x; | |||
| addChild(choice); | |||
| yPos += choice->box.size.y + margin.y; | |||
| } | |||
| { | |||
| Label *label = new Label(); | |||
| label->box.pos = Vec(margin.x, yPos); | |||
| @@ -675,4 +282,11 @@ AudioInterfaceWidget::AudioInterfaceWidget() { | |||
| xPos += 37 + margin.x; | |||
| } | |||
| yPos += 35 + margin.y; | |||
| AudioWidget *audioWidget = construct<USB_B_AudioWidget>(); | |||
| audioWidget->audioIO = &module->audioIO; | |||
| addChild(audioWidget); | |||
| // Widget *w = construct<DIN_MIDIWidget>(); | |||
| // w->box.pos = Vec(100, 0); | |||
| // addChild(w); | |||
| } | |||