@@ -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 | // 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 | // Jacks | ||||
//////////////////// | //////////////////// |
@@ -7,7 +7,7 @@ | |||||
#include "engine.hpp" | #include "engine.hpp" | ||||
#include "gui.hpp" | #include "gui.hpp" | ||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "components.hpp" | |||||
#include "componentlibrary.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -25,6 +25,9 @@ inline Vec mm2px(Vec millimeters) { | |||||
return millimeters.mult(SVG_DPI / 25.4); | return millimeters.mult(SVG_DPI / 25.4); | ||||
} | } | ||||
#define CHECKMARK_STRING "âś”" | |||||
#define CHECKMARK(_cond) ((_cond) ? CHECKMARK_STRING : "") | |||||
//////////////////// | //////////////////// | ||||
// resources | // 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 "app.hpp" | ||||
#include "gui.hpp" | #include "gui.hpp" | ||||
#include "components.hpp" | |||||
#include "engine.hpp" | #include "engine.hpp" | ||||
#include "componentlibrary.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -53,13 +53,13 @@ struct FileChoice : ChoiceButton { | |||||
}; | }; | ||||
struct PauseItem : MenuItem { | |||||
struct EnginePauseItem : MenuItem { | |||||
void onAction(EventAction &e) override { | void onAction(EventAction &e) override { | ||||
gPaused = !gPaused; | gPaused = !gPaused; | ||||
} | } | ||||
}; | }; | ||||
struct SampleRateItem : MenuItem { | |||||
struct EngineSampleRateItem : MenuItem { | |||||
float sampleRate; | float sampleRate; | ||||
void onAction(EventAction &e) override { | void onAction(EventAction &e) override { | ||||
engineSetSampleRate(sampleRate); | engineSetSampleRate(sampleRate); | ||||
@@ -67,22 +67,21 @@ struct SampleRateItem : MenuItem { | |||||
} | } | ||||
}; | }; | ||||
struct SampleRateChoice : ChoiceButton { | |||||
struct EngineSampleRateChoice : ChoiceButton { | |||||
void onAction(EventAction &e) override { | void onAction(EventAction &e) override { | ||||
Menu *menu = gScene->createMenu(); | Menu *menu = gScene->createMenu(); | ||||
menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); | menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); | ||||
menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
PauseItem *pauseItem = new PauseItem(); | |||||
EnginePauseItem *pauseItem = new EnginePauseItem(); | |||||
pauseItem->text = gPaused ? "Resume engine" : "Pause engine"; | pauseItem->text = gPaused ? "Resume engine" : "Pause engine"; | ||||
menu->addChild(pauseItem); | 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); | menu->addChild(item); | ||||
} | } | ||||
} | } | ||||
@@ -112,7 +111,7 @@ Toolbar::Toolbar() { | |||||
xPos += margin; | xPos += margin; | ||||
{ | { | ||||
SampleRateChoice *srChoice = new SampleRateChoice(); | |||||
EngineSampleRateChoice *srChoice = new EngineSampleRateChoice(); | |||||
srChoice->box.pos = Vec(xPos, margin); | srChoice->box.pos = Vec(xPos, margin); | ||||
srChoice->box.size.x = 100; | srChoice->box.size.x = 100; | ||||
addChild(srChoice); | addChild(srChoice); | ||||
@@ -1,6 +1,6 @@ | |||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "engine.hpp" | #include "engine.hpp" | ||||
#include "components.hpp" | |||||
#include "componentlibrary.hpp" | |||||
#include "gui.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 <assert.h> | ||||
#include <mutex> | #include <mutex> | ||||
#include <thread> | #include <thread> | ||||
#include <algorithm> | |||||
#include "core.hpp" | #include "core.hpp" | ||||
#include "audio.hpp" | |||||
#include "dsp/samplerate.hpp" | #include "dsp/samplerate.hpp" | ||||
#include "dsp/ringbuffer.hpp" | #include "dsp/ringbuffer.hpp" | ||||
@@ -29,13 +29,7 @@ struct AudioInterface : Module { | |||||
NUM_OUTPUTS = AUDIO1_OUTPUT + 8 | 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> inputSrc; | ||||
SampleRateConverter<8> outputSrc; | SampleRateConverter<8> outputSrc; | ||||
@@ -47,89 +41,43 @@ struct AudioInterface : Module { | |||||
DoubleRingBuffer<Frame<8>, (1<<15)> inputSrcBuffer; | DoubleRingBuffer<Frame<8>, (1<<15)> inputSrcBuffer; | ||||
AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | AudioInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | ||||
setDriver(RtAudio::UNSPECIFIED); | |||||
} | |||||
~AudioInterface() { | |||||
closeStream(); | |||||
} | } | ||||
void step() override; | void step() override; | ||||
void stepStream(const float *input, float *output, int numFrames); | 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 *toJson() override { | ||||
json_t *rootJ = json_object(); | 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; | return rootJ; | ||||
} | } | ||||
void fromJson(json_t *rootJ) override { | 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 { | void onReset() override { | ||||
closeStream(); | |||||
audioIO.closeStream(); | |||||
} | } | ||||
}; | }; | ||||
@@ -149,15 +97,15 @@ struct AudioInterface : Module { | |||||
void AudioInterface::step() { | void AudioInterface::step() { | ||||
// debug("inputBuffer %d inputSrcBuffer %d outputBuffer %d", inputBuffer.size(), inputSrcBuffer.size(), outputBuffer.size()); | // 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 | // 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); | TIMED_SLEEP_LOCK(!outputBuffer.empty(), 100e-6, 0.2); | ||||
} | } | ||||
// Get input and pass it through the sample rate converter | // Get input and pass it through the sample rate converter | ||||
if (numOutputs > 0) { | |||||
if (audioIO.numOutputs > 0) { | |||||
if (!inputBuffer.full()) { | if (!inputBuffer.full()) { | ||||
Frame<8> f; | Frame<8> f; | ||||
for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
@@ -169,7 +117,7 @@ void AudioInterface::step() { | |||||
// Once full, sample rate convert the input | // Once full, sample rate convert the input | ||||
// inputBuffer -> SRC -> inputSrcBuffer | // inputBuffer -> SRC -> inputSrcBuffer | ||||
if (inputBuffer.full()) { | if (inputBuffer.full()) { | ||||
inputSrc.setRates(engineGetSampleRate(), sampleRate); | |||||
inputSrc.setRates(engineGetSampleRate(), audioIO.sampleRate); | |||||
int inLen = inputBuffer.size(); | int inLen = inputBuffer.size(); | ||||
int outLen = inputSrcBuffer.capacity(); | int outLen = inputSrcBuffer.capacity(); | ||||
inputSrc.process(inputBuffer.startData(), &inLen, inputSrcBuffer.endData(), &outLen); | 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) { | void AudioInterface::stepStream(const float *input, float *output, int numFrames) { | ||||
if (gPaused) { | if (gPaused) { | ||||
memset(output, 0, sizeof(float) * numOutputs * numFrames); | |||||
memset(output, 0, sizeof(float) * audioIO.numOutputs * numFrames); | |||||
return; | return; | ||||
} | } | ||||
if (numOutputs > 0) { | |||||
if (audioIO.numOutputs > 0) { | |||||
// Wait for enough input before proceeding | // Wait for enough input before proceeding | ||||
TIMED_SLEEP_LOCK(inputSrcBuffer.size() >= numFrames, 100e-6, 0.2); | 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); | TIMED_SLEEP_LOCK(outputBuffer.empty(), 100e-6, 0.2); | ||||
} | } | ||||
// input stream -> output buffer | // input stream -> output buffer | ||||
if (numInputs > 0) { | |||||
if (audioIO.numInputs > 0) { | |||||
Frame<8> inputFrames[numFrames]; | Frame<8> inputFrames[numFrames]; | ||||
for (int i = 0; i < numFrames; i++) { | for (int i = 0; i < numFrames; i++) { | ||||
for (int c = 0; c < 8; c++) { | 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 | // Pass output through sample rate converter | ||||
outputSrc.setRates(sampleRate, engineGetSampleRate()); | |||||
outputSrc.setRates(audioIO.sampleRate, engineGetSampleRate()); | |||||
int inLen = numFrames; | int inLen = numFrames; | ||||
int outLen = outputBuffer.capacity(); | int outLen = outputBuffer.capacity(); | ||||
outputSrc.process(inputFrames, &inLen, outputBuffer.endData(), &outLen); | 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 | // input buffer -> output stream | ||||
if (numOutputs > 0) { | |||||
if (audioIO.numOutputs > 0) { | |||||
for (int i = 0; i < numFrames; i++) { | for (int i = 0; i < numFrames; i++) { | ||||
Frame<8> f; | Frame<8> f; | ||||
if (inputSrcBuffer.empty()) { | if (inputSrcBuffer.empty()) { | ||||
@@ -228,304 +176,23 @@ void AudioInterface::stepStream(const float *input, float *output, int numFrames | |||||
else { | else { | ||||
f = inputSrcBuffer.shift(); | 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() { | AudioInterfaceWidget::AudioInterfaceWidget() { | ||||
@@ -545,69 +212,9 @@ AudioInterfaceWidget::AudioInterfaceWidget() { | |||||
Vec margin = Vec(5, 2); | Vec margin = Vec(5, 2); | ||||
float labelHeight = 15; | float labelHeight = 15; | ||||
float yPos = margin.y; | |||||
float yPos = margin.y + 100; | |||||
float xPos; | 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 *label = new Label(); | ||||
label->box.pos = Vec(margin.x, yPos); | label->box.pos = Vec(margin.x, yPos); | ||||
@@ -675,4 +282,11 @@ AudioInterfaceWidget::AudioInterfaceWidget() { | |||||
xPos += 37 + margin.x; | xPos += 37 + margin.x; | ||||
} | } | ||||
yPos += 35 + margin.y; | 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); | |||||
} | } |