Browse Source

Add AudioWidget

tags/v0.6.0
Andrew Belt 6 years ago
parent
commit
f129f026f6
14 changed files with 1605 additions and 450 deletions
  1. +15
    -0
      include/app.hpp
  2. +42
    -0
      include/audio.hpp
  3. +16
    -0
      include/componentlibrary.hpp
  4. +1
    -1
      include/rack.hpp
  5. +3
    -0
      include/widgets.hpp
  6. +366
    -0
      res/ComponentLibrary/ADAT.svg
  7. +397
    -0
      res/ComponentLibrary/MIDI_DIN.svg
  8. +376
    -0
      res/ComponentLibrary/USB-B.svg
  9. +115
    -0
      src/app/AudioWidget.cpp
  10. +1
    -1
      src/app/Port.cpp
  11. +10
    -11
      src/app/Toolbar.cpp
  12. +1
    -1
      src/app/WireWidget.cpp
  13. +212
    -0
      src/audio.cpp
  14. +50
    -436
      src/core/AudioInterface.cpp

+ 15
- 0
include/app.hpp View File

@@ -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
////////////////////


+ 42
- 0
include/audio.hpp View File

@@ -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

include/components.hpp → include/componentlibrary.hpp View File

@@ -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
////////////////////

+ 1
- 1
include/rack.hpp View File

@@ -7,7 +7,7 @@
#include "engine.hpp"
#include "gui.hpp"
#include "app.hpp"
#include "components.hpp"
#include "componentlibrary.hpp"


namespace rack {


+ 3
- 0
include/widgets.hpp View File

@@ -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


+ 366
- 0
res/ComponentLibrary/ADAT.svg View File

@@ -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>

+ 397
- 0
res/ComponentLibrary/MIDI_DIN.svg View File

@@ -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>

+ 376
- 0
res/ComponentLibrary/USB-B.svg View File

@@ -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>

+ 115
- 0
src/app/AudioWidget.cpp View File

@@ -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
- 1
src/app/Port.cpp View File

@@ -1,7 +1,7 @@
#include "app.hpp"
#include "gui.hpp"
#include "components.hpp"
#include "engine.hpp"
#include "componentlibrary.hpp"


namespace rack {


+ 10
- 11
src/app/Toolbar.cpp View File

@@ -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
- 1
src/app/WireWidget.cpp View File

@@ -1,6 +1,6 @@
#include "app.hpp"
#include "engine.hpp"
#include "components.hpp"
#include "componentlibrary.hpp"
#include "gui.hpp"




+ 212
- 0
src/audio.cpp View File

@@ -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

+ 50
- 436
src/core/AudioInterface.cpp View File

@@ -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);
}

Loading…
Cancel
Save