commit
8820089289
@ -0,0 +1 @@ |
|||||||
|
/target |
@ -0,0 +1,11 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<module type="CPP_MODULE" version="4"> |
||||||
|
<component name="NewModuleRootManager"> |
||||||
|
<content url="file://$MODULE_DIR$"> |
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> |
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" /> |
||||||
|
</content> |
||||||
|
<orderEntry type="inheritedJdk" /> |
||||||
|
<orderEntry type="sourceFolder" forTests="false" /> |
||||||
|
</component> |
||||||
|
</module> |
@ -0,0 +1,8 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="ProjectModuleManager"> |
||||||
|
<modules> |
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/beeptestrs.iml" filepath="$PROJECT_DIR$/.idea/beeptestrs.iml" /> |
||||||
|
</modules> |
||||||
|
</component> |
||||||
|
</project> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="VcsDirectoryMappings"> |
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" /> |
||||||
|
</component> |
||||||
|
</project> |
@ -0,0 +1,138 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="CMakeRunConfigurationManager" shouldGenerate="true" shouldDeleteObsolete="true"> |
||||||
|
<generated /> |
||||||
|
</component> |
||||||
|
<component name="CMakeSettings"> |
||||||
|
<configurations> |
||||||
|
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" /> |
||||||
|
</configurations> |
||||||
|
</component> |
||||||
|
<component name="CargoProjects"> |
||||||
|
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" /> |
||||||
|
</component> |
||||||
|
<component name="ChangeListManager"> |
||||||
|
<list default="true" id="10cd9b57-3049-40f7-975a-a181479596b3" name="Default Changelist" comment=""> |
||||||
|
<change afterPath="$PROJECT_DIR$/src/beep/osc.rs" afterDir="false" /> |
||||||
|
</list> |
||||||
|
<option name="SHOW_DIALOG" value="false" /> |
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" /> |
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> |
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" /> |
||||||
|
</component> |
||||||
|
<component name="ClangdSettings"> |
||||||
|
<option name="formatViaClangd" value="false" /> |
||||||
|
</component> |
||||||
|
<component name="FileColors"> |
||||||
|
<fileColor scope="Non-Project Files (Material Default)" color="2E3C43" /> |
||||||
|
<fileColor scope="Non-Project Files (Material Darker)" color="323232" /> |
||||||
|
<fileColor scope="Non-Project Files (Material Lighter)" color="eae8e8" /> |
||||||
|
<fileColor scope="Non-Project Files (Material Palenight)" color="2f2e43" /> |
||||||
|
</component> |
||||||
|
<component name="FileTemplateManagerImpl"> |
||||||
|
<option name="RECENT_TEMPLATES"> |
||||||
|
<list> |
||||||
|
<option value="Rust File" /> |
||||||
|
</list> |
||||||
|
</option> |
||||||
|
</component> |
||||||
|
<component name="Git.Settings"> |
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> |
||||||
|
</component> |
||||||
|
<component name="MacroExpansionManager"> |
||||||
|
<option name="directoryName" value="zqz5wsij" /> |
||||||
|
</component> |
||||||
|
<component name="ProjectId" id="1jMxUiuWWUW9kd7fLhEhnNAF1kh" /> |
||||||
|
<component name="ProjectViewState"> |
||||||
|
<option name="hideEmptyMiddlePackages" value="true" /> |
||||||
|
<option name="showLibraryContents" value="true" /> |
||||||
|
</component> |
||||||
|
<component name="PropertiesComponent"> |
||||||
|
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" /> |
||||||
|
<property name="WebServerToolWindowFactoryState" value="false" /> |
||||||
|
<property name="cf.first.check.clang-format" value="false" /> |
||||||
|
<property name="node.js.detected.package.eslint" value="true" /> |
||||||
|
<property name="node.js.detected.package.tslint" value="true" /> |
||||||
|
<property name="node.js.path.for.package.eslint" value="project" /> |
||||||
|
<property name="node.js.path.for.package.tslint" value="project" /> |
||||||
|
<property name="node.js.selected.package.eslint" value="(autodetect)" /> |
||||||
|
<property name="node.js.selected.package.tslint" value="(autodetect)" /> |
||||||
|
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" /> |
||||||
|
<property name="nodejs_npm_path_reset_for_default_project" value="true" /> |
||||||
|
<property name="org.rust.cargo.project.model.PROJECT_DISCOVERY" value="true" /> |
||||||
|
<property name="settings.editor.selected.configurable" value="editor.preferences.gutterIcons" /> |
||||||
|
</component> |
||||||
|
<component name="RunManager"> |
||||||
|
<configuration name="Run" type="CargoCommandRunConfiguration" factoryName="Cargo Command"> |
||||||
|
<option name="channel" value="DEFAULT" /> |
||||||
|
<option name="command" value="run --package beeptestrs --bin beeptestrs" /> |
||||||
|
<option name="allFeatures" value="false" /> |
||||||
|
<option name="emulateTerminal" value="false" /> |
||||||
|
<option name="backtrace" value="SHORT" /> |
||||||
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" /> |
||||||
|
<envs /> |
||||||
|
<method v="2"> |
||||||
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" /> |
||||||
|
</method> |
||||||
|
</configuration> |
||||||
|
<configuration default="true" type="CargoCommandRunConfiguration" factoryName="Cargo Command"> |
||||||
|
<option name="channel" value="DEFAULT" /> |
||||||
|
<option name="command" value="run" /> |
||||||
|
<option name="allFeatures" value="false" /> |
||||||
|
<option name="emulateTerminal" value="false" /> |
||||||
|
<option name="backtrace" value="SHORT" /> |
||||||
|
<envs /> |
||||||
|
<method v="2"> |
||||||
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" /> |
||||||
|
</method> |
||||||
|
</configuration> |
||||||
|
</component> |
||||||
|
<component name="RustProjectSettings"> |
||||||
|
<option name="toolchainHomeDirectory" value="/usr/bin" /> |
||||||
|
</component> |
||||||
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" /> |
||||||
|
<component name="TaskManager"> |
||||||
|
<task active="true" id="Default" summary="Default task"> |
||||||
|
<changelist id="10cd9b57-3049-40f7-975a-a181479596b3" name="Default Changelist" comment="" /> |
||||||
|
<created>1603627779596</created> |
||||||
|
<option name="number" value="Default" /> |
||||||
|
<option name="presentableId" value="Default" /> |
||||||
|
<updated>1603627779596</updated> |
||||||
|
<workItem from="1603627780818" duration="18022000" /> |
||||||
|
</task> |
||||||
|
<servers /> |
||||||
|
</component> |
||||||
|
<component name="TypeScriptGeneratedFilesManager"> |
||||||
|
<option name="version" value="3" /> |
||||||
|
</component> |
||||||
|
<component name="WindowStateProjectService"> |
||||||
|
<state x="769" y="331" key="#com.intellij.ide.util.MemberChooser" timestamp="1603643362566"> |
||||||
|
<screen x="0" y="32" width="1920" height="1168" /> |
||||||
|
</state> |
||||||
|
<state x="769" y="331" key="#com.intellij.ide.util.MemberChooser/0.32.1920.1168/1920.0.1600.1200@0.32.1920.1168" timestamp="1603643362566" /> |
||||||
|
<state width="1600" height="1109" key="GridCell.Tab.0.bottom" timestamp="1603650855702"> |
||||||
|
<screen x="0" y="32" width="1920" height="1168" /> |
||||||
|
</state> |
||||||
|
<state width="1600" height="1109" key="GridCell.Tab.0.bottom/0.32.1920.1168/1920.0.1600.1200@0.32.1920.1168" timestamp="1603650855702" /> |
||||||
|
<state width="1600" height="1109" key="GridCell.Tab.0.center" timestamp="1603650855702"> |
||||||
|
<screen x="0" y="32" width="1920" height="1168" /> |
||||||
|
</state> |
||||||
|
<state width="1600" height="1109" key="GridCell.Tab.0.center/0.32.1920.1168/1920.0.1600.1200@0.32.1920.1168" timestamp="1603650855702" /> |
||||||
|
<state width="1600" height="1109" key="GridCell.Tab.0.left" timestamp="1603650855702"> |
||||||
|
<screen x="0" y="32" width="1920" height="1168" /> |
||||||
|
</state> |
||||||
|
<state width="1600" height="1109" key="GridCell.Tab.0.left/0.32.1920.1168/1920.0.1600.1200@0.32.1920.1168" timestamp="1603650855702" /> |
||||||
|
<state width="1600" height="1109" key="GridCell.Tab.0.right" timestamp="1603650855702"> |
||||||
|
<screen x="0" y="32" width="1920" height="1168" /> |
||||||
|
</state> |
||||||
|
<state width="1600" height="1109" key="GridCell.Tab.0.right/0.32.1920.1168/1920.0.1600.1200@0.32.1920.1168" timestamp="1603650855702" /> |
||||||
|
<state x="651" y="325" width="635" height="580" key="find.popup" timestamp="1603633050478"> |
||||||
|
<screen x="0" y="32" width="1920" height="1168" /> |
||||||
|
</state> |
||||||
|
<state x="651" y="325" width="635" height="580" key="find.popup/0.32.1920.1168/1920.0.1600.1200@0.32.1920.1168" timestamp="1603633050478" /> |
||||||
|
<state width="1007" height="578" key="javadoc.popup.new" timestamp="1603640885345"> |
||||||
|
<screen x="0" y="32" width="1920" height="1168" /> |
||||||
|
</state> |
||||||
|
<state width="1007" height="578" key="javadoc.popup.new/0.32.1920.1168/1920.0.1600.1200@0.32.1920.1168" timestamp="1603640885345" /> |
||||||
|
</component> |
||||||
|
</project> |
@ -0,0 +1,596 @@ |
|||||||
|
# This file is automatically @generated by Cargo. |
||||||
|
# It is not intended for manual editing. |
||||||
|
[[package]] |
||||||
|
name = "alsa" |
||||||
|
version = "0.4.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "44581add1add74ade32aca327b550342359ec00191672c23c1caa3d492b85930" |
||||||
|
dependencies = [ |
||||||
|
"alsa-sys", |
||||||
|
"bitflags", |
||||||
|
"libc", |
||||||
|
"nix", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "alsa-sys" |
||||||
|
version = "0.3.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "d5a0559bcd3f7a482690d98be41c08a43e92f669b179433e95ddf5e8b8fd36a3" |
||||||
|
dependencies = [ |
||||||
|
"libc", |
||||||
|
"pkg-config", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "anyhow" |
||||||
|
version = "1.0.33" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "beeptestrs" |
||||||
|
version = "0.1.0" |
||||||
|
dependencies = [ |
||||||
|
"anyhow", |
||||||
|
"cpal", |
||||||
|
"parking_lot 0.11.0", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "bindgen" |
||||||
|
version = "0.53.3" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5" |
||||||
|
dependencies = [ |
||||||
|
"bitflags", |
||||||
|
"cexpr", |
||||||
|
"cfg-if 0.1.10", |
||||||
|
"clang-sys", |
||||||
|
"lazy_static", |
||||||
|
"lazycell", |
||||||
|
"peeking_take_while", |
||||||
|
"proc-macro2", |
||||||
|
"quote", |
||||||
|
"regex", |
||||||
|
"rustc-hash", |
||||||
|
"shlex", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "bitflags" |
||||||
|
version = "1.2.1" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "bumpalo" |
||||||
|
version = "3.4.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "cc" |
||||||
|
version = "1.0.61" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "cexpr" |
||||||
|
version = "0.4.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" |
||||||
|
dependencies = [ |
||||||
|
"nom", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "cfg-if" |
||||||
|
version = "0.1.10" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "cfg-if" |
||||||
|
version = "1.0.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "clang-sys" |
||||||
|
version = "0.29.3" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" |
||||||
|
dependencies = [ |
||||||
|
"glob", |
||||||
|
"libc", |
||||||
|
"libloading", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "cloudabi" |
||||||
|
version = "0.0.3" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" |
||||||
|
dependencies = [ |
||||||
|
"bitflags", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "cloudabi" |
||||||
|
version = "0.1.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" |
||||||
|
dependencies = [ |
||||||
|
"bitflags", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "core-foundation-sys" |
||||||
|
version = "0.6.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "coreaudio-rs" |
||||||
|
version = "0.9.1" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "f229761965dad3e9b11081668a6ea00f1def7aa46062321b5ec245b834f6e491" |
||||||
|
dependencies = [ |
||||||
|
"bitflags", |
||||||
|
"coreaudio-sys", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "coreaudio-sys" |
||||||
|
version = "0.2.5" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "d6570ee6e089131e928d5ec9236db9e818aa3cf850f48b0eec6ef700571271d4" |
||||||
|
dependencies = [ |
||||||
|
"bindgen", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "cpal" |
||||||
|
version = "0.12.1" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "be4410231e181e24e3e4612dfca601601e40942003e6a52a12d9d80f19fd9737" |
||||||
|
dependencies = [ |
||||||
|
"alsa", |
||||||
|
"core-foundation-sys", |
||||||
|
"coreaudio-rs", |
||||||
|
"js-sys", |
||||||
|
"lazy_static", |
||||||
|
"libc", |
||||||
|
"mach", |
||||||
|
"nix", |
||||||
|
"parking_lot 0.9.0", |
||||||
|
"stdweb", |
||||||
|
"thiserror", |
||||||
|
"web-sys", |
||||||
|
"winapi", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "glob" |
||||||
|
version = "0.3.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "instant" |
||||||
|
version = "0.1.8" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613" |
||||||
|
dependencies = [ |
||||||
|
"cfg-if 1.0.0", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "js-sys" |
||||||
|
version = "0.3.45" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" |
||||||
|
dependencies = [ |
||||||
|
"wasm-bindgen", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "lazy_static" |
||||||
|
version = "1.4.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "lazycell" |
||||||
|
version = "1.3.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "libc" |
||||||
|
version = "0.2.79" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "libloading" |
||||||
|
version = "0.5.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" |
||||||
|
dependencies = [ |
||||||
|
"cc", |
||||||
|
"winapi", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "lock_api" |
||||||
|
version = "0.3.4" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" |
||||||
|
dependencies = [ |
||||||
|
"scopeguard", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "lock_api" |
||||||
|
version = "0.4.1" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" |
||||||
|
dependencies = [ |
||||||
|
"scopeguard", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "log" |
||||||
|
version = "0.4.11" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" |
||||||
|
dependencies = [ |
||||||
|
"cfg-if 0.1.10", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "mach" |
||||||
|
version = "0.3.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" |
||||||
|
dependencies = [ |
||||||
|
"libc", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "maybe-uninit" |
||||||
|
version = "2.0.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "memchr" |
||||||
|
version = "2.3.3" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "nix" |
||||||
|
version = "0.15.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" |
||||||
|
dependencies = [ |
||||||
|
"bitflags", |
||||||
|
"cc", |
||||||
|
"cfg-if 0.1.10", |
||||||
|
"libc", |
||||||
|
"void", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "nom" |
||||||
|
version = "5.1.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" |
||||||
|
dependencies = [ |
||||||
|
"memchr", |
||||||
|
"version_check", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "parking_lot" |
||||||
|
version = "0.9.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" |
||||||
|
dependencies = [ |
||||||
|
"lock_api 0.3.4", |
||||||
|
"parking_lot_core 0.6.2", |
||||||
|
"rustc_version", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "parking_lot" |
||||||
|
version = "0.11.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733" |
||||||
|
dependencies = [ |
||||||
|
"instant", |
||||||
|
"lock_api 0.4.1", |
||||||
|
"parking_lot_core 0.8.0", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "parking_lot_core" |
||||||
|
version = "0.6.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" |
||||||
|
dependencies = [ |
||||||
|
"cfg-if 0.1.10", |
||||||
|
"cloudabi 0.0.3", |
||||||
|
"libc", |
||||||
|
"redox_syscall", |
||||||
|
"rustc_version", |
||||||
|
"smallvec 0.6.13", |
||||||
|
"winapi", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "parking_lot_core" |
||||||
|
version = "0.8.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" |
||||||
|
dependencies = [ |
||||||
|
"cfg-if 0.1.10", |
||||||
|
"cloudabi 0.1.0", |
||||||
|
"instant", |
||||||
|
"libc", |
||||||
|
"redox_syscall", |
||||||
|
"smallvec 1.4.2", |
||||||
|
"winapi", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "peeking_take_while" |
||||||
|
version = "0.1.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "pkg-config" |
||||||
|
version = "0.3.19" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "proc-macro2" |
||||||
|
version = "1.0.24" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" |
||||||
|
dependencies = [ |
||||||
|
"unicode-xid", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "quote" |
||||||
|
version = "1.0.7" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" |
||||||
|
dependencies = [ |
||||||
|
"proc-macro2", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "redox_syscall" |
||||||
|
version = "0.1.57" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "regex" |
||||||
|
version = "1.4.1" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "8963b85b8ce3074fecffde43b4b0dded83ce2f367dc8d363afc56679f3ee820b" |
||||||
|
dependencies = [ |
||||||
|
"regex-syntax", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "regex-syntax" |
||||||
|
version = "0.6.20" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "8cab7a364d15cde1e505267766a2d3c4e22a843e1a601f0fa7564c0f82ced11c" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "rustc-hash" |
||||||
|
version = "1.1.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "rustc_version" |
||||||
|
version = "0.2.3" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" |
||||||
|
dependencies = [ |
||||||
|
"semver", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "scopeguard" |
||||||
|
version = "1.1.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "semver" |
||||||
|
version = "0.9.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" |
||||||
|
dependencies = [ |
||||||
|
"semver-parser", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "semver-parser" |
||||||
|
version = "0.7.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "shlex" |
||||||
|
version = "0.1.1" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "smallvec" |
||||||
|
version = "0.6.13" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" |
||||||
|
dependencies = [ |
||||||
|
"maybe-uninit", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "smallvec" |
||||||
|
version = "1.4.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "stdweb" |
||||||
|
version = "0.1.3" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "syn" |
||||||
|
version = "1.0.48" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" |
||||||
|
dependencies = [ |
||||||
|
"proc-macro2", |
||||||
|
"quote", |
||||||
|
"unicode-xid", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "thiserror" |
||||||
|
version = "1.0.21" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" |
||||||
|
dependencies = [ |
||||||
|
"thiserror-impl", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "thiserror-impl" |
||||||
|
version = "1.0.21" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" |
||||||
|
dependencies = [ |
||||||
|
"proc-macro2", |
||||||
|
"quote", |
||||||
|
"syn", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "unicode-xid" |
||||||
|
version = "0.2.1" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "version_check" |
||||||
|
version = "0.9.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "void" |
||||||
|
version = "1.0.2" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "wasm-bindgen" |
||||||
|
version = "0.2.68" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" |
||||||
|
dependencies = [ |
||||||
|
"cfg-if 0.1.10", |
||||||
|
"wasm-bindgen-macro", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "wasm-bindgen-backend" |
||||||
|
version = "0.2.68" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" |
||||||
|
dependencies = [ |
||||||
|
"bumpalo", |
||||||
|
"lazy_static", |
||||||
|
"log", |
||||||
|
"proc-macro2", |
||||||
|
"quote", |
||||||
|
"syn", |
||||||
|
"wasm-bindgen-shared", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "wasm-bindgen-macro" |
||||||
|
version = "0.2.68" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" |
||||||
|
dependencies = [ |
||||||
|
"quote", |
||||||
|
"wasm-bindgen-macro-support", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "wasm-bindgen-macro-support" |
||||||
|
version = "0.2.68" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" |
||||||
|
dependencies = [ |
||||||
|
"proc-macro2", |
||||||
|
"quote", |
||||||
|
"syn", |
||||||
|
"wasm-bindgen-backend", |
||||||
|
"wasm-bindgen-shared", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "wasm-bindgen-shared" |
||||||
|
version = "0.2.68" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "web-sys" |
||||||
|
version = "0.3.45" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" |
||||||
|
dependencies = [ |
||||||
|
"js-sys", |
||||||
|
"wasm-bindgen", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "winapi" |
||||||
|
version = "0.3.9" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" |
||||||
|
dependencies = [ |
||||||
|
"winapi-i686-pc-windows-gnu", |
||||||
|
"winapi-x86_64-pc-windows-gnu", |
||||||
|
] |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "winapi-i686-pc-windows-gnu" |
||||||
|
version = "0.4.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" |
||||||
|
|
||||||
|
[[package]] |
||||||
|
name = "winapi-x86_64-pc-windows-gnu" |
||||||
|
version = "0.4.0" |
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" |
@ -0,0 +1,12 @@ |
|||||||
|
[package] |
||||||
|
name = "beeptestrs" |
||||||
|
version = "0.1.0" |
||||||
|
authors = ["Ondřej Hruška <ondra@ondrovo.com>"] |
||||||
|
edition = "2018" |
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
cpal = "0.12.1" |
||||||
|
anyhow = "1.0.33" |
||||||
|
parking_lot = "0.11.0" |
@ -0,0 +1,152 @@ |
|||||||
|
use std::sync::Arc; |
||||||
|
|
||||||
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; |
||||||
|
use std::ops::{Add, AddAssign, Sub}; |
||||||
|
use parking_lot::RwLock; |
||||||
|
use std::time::Duration; |
||||||
|
use std::thread; |
||||||
|
use cpal::SampleFormat; |
||||||
|
use crate::beep::osc::{Instrument, Oscillator}; |
||||||
|
|
||||||
|
pub mod osc; |
||||||
|
|
||||||
|
struct AudioContext { |
||||||
|
device: cpal::Device, |
||||||
|
sample_format: SampleFormat, |
||||||
|
config: cpal::StreamConfig |
||||||
|
} |
||||||
|
|
||||||
|
fn al_init() -> Result<AudioContext, anyhow::Error> { |
||||||
|
let host = cpal::default_host(); |
||||||
|
|
||||||
|
let device = host.default_output_device() |
||||||
|
.ok_or_else(|| anyhow::anyhow!("No audio output device!"))?; |
||||||
|
|
||||||
|
let config = device.default_output_config()?; |
||||||
|
|
||||||
|
Ok(AudioContext { |
||||||
|
device, |
||||||
|
sample_format: config.sample_format(), |
||||||
|
config: config.into() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn beep() -> Result<(), anyhow::Error> { |
||||||
|
let ac = al_init()?; |
||||||
|
|
||||||
|
match ac.sample_format { |
||||||
|
cpal::SampleFormat::F32 => run::<f32>(&ac.device, &ac.config.into())?, |
||||||
|
cpal::SampleFormat::I16 => run::<i16>(&ac.device, &ac.config.into())?, |
||||||
|
cpal::SampleFormat::U16 => run::<u16>(&ac.device, &ac.config.into())?, |
||||||
|
} |
||||||
|
|
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyhow::Error> |
||||||
|
where |
||||||
|
T: cpal::Sample, |
||||||
|
{ |
||||||
|
let sample_rate = config.sample_rate.0 as f32; |
||||||
|
let channels = config.channels as usize; |
||||||
|
|
||||||
|
println!("SR={}",sample_rate); |
||||||
|
|
||||||
|
// Produce a sinusoid of maximum amplitude.
|
||||||
|
|
||||||
|
let mut ins = Instrument::new(vec![ |
||||||
|
Oscillator::new(440.0, 1.0, sample_rate), |
||||||
|
//Oscillator::new(441.0, 1.0, sample_rate),
|
||||||
|
], sample_rate); |
||||||
|
|
||||||
|
let instrument = Arc::new(parking_lot::RwLock::new(ins)); |
||||||
|
|
||||||
|
let err_fn = |err| eprintln!("an error occurred on stream: {}", err); |
||||||
|
|
||||||
|
let m_instrument = instrument.clone(); |
||||||
|
let stream = device.build_output_stream( |
||||||
|
config, |
||||||
|
move |data: &mut [T], _: &cpal::OutputCallbackInfo| { |
||||||
|
write_data(data, channels, &m_instrument) |
||||||
|
}, |
||||||
|
err_fn, |
||||||
|
)?; |
||||||
|
stream.play()?; |
||||||
|
|
||||||
|
// instrument.write().normalize(false);
|
||||||
|
// instrument.write().set_amp(1.0);
|
||||||
|
// thread::sleep(Duration::from_millis(500));
|
||||||
|
//
|
||||||
|
// instrument.write().set_amp(0.0);
|
||||||
|
// thread::sleep(Duration::from_millis(250));
|
||||||
|
|
||||||
|
instrument.write().set_amp(1.0); |
||||||
|
instrument.write().normalize(true); |
||||||
|
thread::sleep(Duration::from_millis(500)); |
||||||
|
|
||||||
|
instrument.write().set_amp(0.0); |
||||||
|
thread::sleep(Duration::from_millis(250)); |
||||||
|
|
||||||
|
instrument.write().set_amp(0.5); |
||||||
|
thread::sleep(Duration::from_millis(500)); |
||||||
|
|
||||||
|
instrument.write().set_amp(0.0); |
||||||
|
thread::sleep(Duration::from_millis(250)); |
||||||
|
|
||||||
|
instrument.write().fade_amp(1.0, Duration::from_millis(10)); |
||||||
|
instrument.write().waveforms[0].fade_balance(-1.0, Duration::from_millis(10)); |
||||||
|
thread::sleep(Duration::from_millis(500)); |
||||||
|
instrument.write().fade_amp(0.0, Duration::from_millis(10)); |
||||||
|
thread::sleep(Duration::from_millis(500)); |
||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
|
||||||
|
//instrument.write().set_amp_fade(0.0, 4.0);
|
||||||
|
|
||||||
|
thread::sleep(Duration::from_millis(1000)); |
||||||
|
instrument.write().waveforms[1].fade_amp(0.0, Duration::from_millis(500)); |
||||||
|
thread::sleep(Duration::from_millis(500)); |
||||||
|
|
||||||
|
instrument.write().waveforms[0].fade_balance(-1.0, Duration::from_millis(1000)); |
||||||
|
thread::sleep(Duration::from_millis(1000)); |
||||||
|
instrument.write().waveforms[0].fade_balance(1.0, Duration::from_millis(2000)); |
||||||
|
instrument.write().waveforms[0].fade_freq(880.0, Duration::from_millis(1000)); |
||||||
|
thread::sleep(Duration::from_millis(2000)); |
||||||
|
instrument.write().waveforms[0].fade_balance(-1.0, Duration::from_millis(1000)); |
||||||
|
instrument.write().waveforms[0].fade_amp(0.0, Duration::from_millis(1000)); |
||||||
|
thread::sleep(Duration::from_millis(1000)); |
||||||
|
*/ |
||||||
|
|
||||||
|
// for _ in 0..10
|
||||||
|
// {
|
||||||
|
// instrument.write().harmonics[0].set_balance_fade(-1.0, 0.1);
|
||||||
|
// thread::sleep(Duration::from_millis(100));
|
||||||
|
// instrument.write().harmonics[0].set_balance_fade(1.0, 0.1);
|
||||||
|
// thread::sleep(Duration::from_millis(100));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// instrument.write().harmonics[0].set_balance_fade(0.0, 0.5);
|
||||||
|
// instrument.write().harmonics[0].set_amp_fade(0.0, 0.05);
|
||||||
|
// thread::sleep(Duration::from_millis(200));
|
||||||
|
|
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
fn write_data<T>(output: &mut [T], channels: usize, instrument: &Arc<RwLock<Instrument>>) |
||||||
|
where |
||||||
|
T: cpal::Sample, |
||||||
|
{ |
||||||
|
let mut instrument = instrument.write(); |
||||||
|
for frame in output.chunks_mut(channels) { |
||||||
|
let sample = instrument.sample(); |
||||||
|
|
||||||
|
if channels == 1 { |
||||||
|
frame[0] = cpal::Sample::from::<f32>(&((sample.left + sample.right) / 2.0)); |
||||||
|
} else { |
||||||
|
frame[0] = cpal::Sample::from::<f32>(&sample.left); |
||||||
|
frame[1] = cpal::Sample::from::<f32>(&sample.right); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,424 @@ |
|||||||
|
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign}; |
||||||
|
use std::sync::Arc; |
||||||
|
use std::time::Duration; |
||||||
|
|
||||||
|
use parking_lot::RwLock; |
||||||
|
|
||||||
|
use hack::StableClamp; |
||||||
|
|
||||||
|
mod hack { |
||||||
|
/// Work-around for `f32::clamp()` being unstable
|
||||||
|
pub(super) trait StableClamp { |
||||||
|
fn clamp_(self, min: f32, max: f32) -> f32; |
||||||
|
} |
||||||
|
|
||||||
|
impl StableClamp for f32 { |
||||||
|
fn clamp_(self, min: f32, max: f32) -> f32 { |
||||||
|
assert!(min <= max); |
||||||
|
let mut x = self; |
||||||
|
if x < min { |
||||||
|
x = min; |
||||||
|
} |
||||||
|
if x > max { |
||||||
|
x = max; |
||||||
|
} |
||||||
|
x |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Value fader
|
||||||
|
#[derive(Clone,Debug)] |
||||||
|
struct Tween { |
||||||
|
/// Actual value
|
||||||
|
actual: f32, |
||||||
|
/// Target value, approached by adding "step" to :actual" every sample
|
||||||
|
target: f32, |
||||||
|
/// Value added to "actual" per sample. None = set to target at the end of a cycle
|
||||||
|
step: Option<f32>, |
||||||
|
// Min value
|
||||||
|
min: f32, |
||||||
|
// Max value
|
||||||
|
max: f32, |
||||||
|
} |
||||||
|
|
||||||
|
/// Scale function amplitude by a gain
|
||||||
|
trait GainScale { |
||||||
|
fn scale_gain(self, gain: f32) -> Self; |
||||||
|
} |
||||||
|
|
||||||
|
impl GainScale for f32 { |
||||||
|
/// Scale by gain 0-1
|
||||||
|
fn scale_gain(self, gain: f32) -> Self { |
||||||
|
// TODO what scaling to use?
|
||||||
|
// self * (1.0 + gain * 9.0).log10()
|
||||||
|
// self * gain.sqrt()
|
||||||
|
self * gain |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Tween { |
||||||
|
/// Update values for the next sample
|
||||||
|
pub fn tick(&mut self) { |
||||||
|
if let Some(step) = self.step { |
||||||
|
let actual0 = self.actual; |
||||||
|
self.actual += step; |
||||||
|
if (self.target > actual0 && self.target <= self.actual) |
||||||
|
|| (self.target <= actual0 && self.target > self.actual) |
||||||
|
{ |
||||||
|
self.step = None; |
||||||
|
self.actual = self.target; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Get actual value
|
||||||
|
pub fn actual(&self) -> f32 { |
||||||
|
self.actual |
||||||
|
} |
||||||
|
|
||||||
|
/// Check if the change from actual to target is scheduled to happen instantly
|
||||||
|
/// at the end of a cycle.
|
||||||
|
pub fn is_change_scheduled_at_crossover(&self) -> bool { |
||||||
|
self.target != self.actual |
||||||
|
&& self.step.is_none() |
||||||
|
} |
||||||
|
|
||||||
|
/// Check if the fading is in progress
|
||||||
|
pub fn is_fading(&self) -> bool { |
||||||
|
self.step.is_some() |
||||||
|
} |
||||||
|
|
||||||
|
/// Schedule change at crossover
|
||||||
|
fn set_at_crossover(&mut self, val: f32) { |
||||||
|
self.target = val.clamp_(self.min, self.max); |
||||||
|
self.step = None; // change at the earliest convenience
|
||||||
|
} |
||||||
|
|
||||||
|
/// Start fading
|
||||||
|
fn fade(&mut self, val: f32, time: Duration, sample_rate: f32) { |
||||||
|
self.target = val.clamp_(self.min, self.max); |
||||||
|
let nsamples = (time.as_secs_f32() * sample_rate).ceil(); |
||||||
|
self.step = Some((self.target - self.actual) / nsamples); |
||||||
|
} |
||||||
|
|
||||||
|
/// Set value immediately
|
||||||
|
fn set_immediate(&mut self, val: f32) { |
||||||
|
self.target = val; |
||||||
|
self.actual = val; |
||||||
|
self.step = None; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone,Debug)] |
||||||
|
pub struct Oscillator { |
||||||
|
/// Amplitude fader 0..1
|
||||||
|
gain: Tween, |
||||||
|
/// Frequency fader 1..22050
|
||||||
|
freq: Tween, |
||||||
|
/// Balance fader -1..1
|
||||||
|
balance: Tween, |
||||||
|
/// Left channel multiplier
|
||||||
|
gain_left: f32, |
||||||
|
/// Right channel multiplier
|
||||||
|
gain_right: f32, |
||||||
|
/// Sample rate (Hz)
|
||||||
|
sample_rate: f32, |
||||||
|
/// Phase increment per sample
|
||||||
|
phase_step: f32, |
||||||
|
/// Phase 0-TAU
|
||||||
|
phase: f32, |
||||||
|
} |
||||||
|
|
||||||
|
impl Oscillator { |
||||||
|
/// New oscillator with a frequency and amplitude
|
||||||
|
pub fn new(freq: f32, amp: f32, sample_rate : f32) -> Self { |
||||||
|
let mut o = Self { |
||||||
|
gain: Tween { |
||||||
|
actual: amp, |
||||||
|
target: amp, |
||||||
|
min: 0.0, |
||||||
|
max: 1.0, |
||||||
|
step: None |
||||||
|
}, |
||||||
|
freq: Tween { |
||||||
|
actual: freq, |
||||||
|
target: freq, |
||||||
|
min: 1.0, |
||||||
|
max: sample_rate / 2.0, |
||||||
|
step: None |
||||||
|
}, |
||||||
|
balance: Tween { |
||||||
|
actual: 0.0, |
||||||
|
target: 0.0, |
||||||
|
min: -1.0, |
||||||
|
max: 1.0, |
||||||
|
step: None |
||||||
|
}, |
||||||
|
phase_step: 0.0, |
||||||
|
gain_left: 0.0, |
||||||
|
gain_right: 0.0, |
||||||
|
sample_rate, |
||||||
|
phase: 0.0 |
||||||
|
}; |
||||||
|
o.update_step(); |
||||||
|
o.update_gains(1.0); |
||||||
|
o |
||||||
|
} |
||||||
|
|
||||||
|
/// Update the step variable
|
||||||
|
fn update_step(&mut self) { |
||||||
|
self.phase_step = (self.freq.actual / self.sample_rate) * std::f32::consts::TAU; |
||||||
|
} |
||||||
|
|
||||||
|
/// Update the pre-computed channel gain variables
|
||||||
|
fn update_gains(&mut self, gain_scale: f32) { |
||||||
|
let angle = ((1.0 + self.balance.actual) / 2.0) * std::f32::consts::FRAC_PI_2; |
||||||
|
let act = self.gain.actual * gain_scale; |
||||||
|
self.gain_left = act.scale_gain(angle.sin()); |
||||||
|
self.gain_right = act.scale_gain(angle.cos()); |
||||||
|
} |
||||||
|
|
||||||
|
/// Get actual amplitude (0..1)
|
||||||
|
pub fn get_amp(&self) -> f32 { |
||||||
|
self.gain.actual |
||||||
|
} |
||||||
|
|
||||||
|
/// Set amplitude (0..1), change at the end of the current waveform to reduce popping
|
||||||
|
pub fn set_amp(&mut self, amp : f32) { |
||||||
|
self.gain.set_at_crossover(amp); |
||||||
|
} |
||||||
|
|
||||||
|
/// Fade to amplitude (0..1) over a given time
|
||||||
|
pub fn fade_amp(&mut self, amp : f32, time: Duration) { |
||||||
|
self.gain.fade(amp, time, self.sample_rate); |
||||||
|
} |
||||||
|
|
||||||
|
/// Get balance value (-1..1)
|
||||||
|
pub fn get_balance(&self) -> f32 { |
||||||
|
self.balance.actual |
||||||
|
} |
||||||
|
|
||||||
|
/// Set balance (-1..1), change at the end of the current waveform to reduce popping
|
||||||
|
pub fn set_balance(&mut self, balance : f32) { |
||||||
|
self.balance.set_at_crossover(balance); |
||||||
|
} |
||||||
|
|
||||||
|
/// Fade to balance (-1..1) over a given time
|
||||||
|
pub fn fade_balance(&mut self, balance : f32, time: Duration) { |
||||||
|
self.balance.fade(balance, time, self.sample_rate); |
||||||
|
} |
||||||
|
|
||||||
|
/// Get frequency value (1..22050)
|
||||||
|
pub fn get_freq(&self) -> f32 { |
||||||
|
self.freq.actual |
||||||
|
} |
||||||
|
|
||||||
|
/// Set frequency (1..22050), change at the end of the current waveform to reduce popping
|
||||||
|
pub fn set_freq(&mut self, freq : f32) { |
||||||
|
self.freq.set_at_crossover(freq); |
||||||
|
} |
||||||
|
|
||||||
|
/// Fade to frequency (1..22050) over a given time
|
||||||
|
pub fn fade_freq(&mut self, freq : f32, time: Duration) { |
||||||
|
self.freq.fade(freq, time, self.sample_rate); |
||||||
|
} |
||||||
|
|
||||||
|
/// Take a sample. Mutable to update faders.
|
||||||
|
pub fn sample(&mut self, gain_scale: f32) -> StereoSample { |
||||||
|
if self.freq.is_fading() { |
||||||
|
self.freq.tick(); |
||||||
|
self.update_step(); |
||||||
|
} |
||||||
|
|
||||||
|
if self.balance.is_fading() || self.gain.is_fading() { |
||||||
|
self.balance.tick(); |
||||||
|
self.gain.tick(); |
||||||
|
self.update_gains(gain_scale); |
||||||
|
} |
||||||
|
|
||||||
|
let ph0 = self.phase; |
||||||
|
self.phase = (self.phase + self.phase_step) % std::f32::consts::TAU; |
||||||
|
|
||||||
|
// "zero crossing detection"
|
||||||
|
if self.phase < ph0 { |
||||||
|
if self.gain.is_change_scheduled_at_crossover() { |
||||||
|
self.gain.actual = self.gain.target; |
||||||
|
self.update_gains(gain_scale); |
||||||
|
} |
||||||
|
|
||||||
|
if self.balance.is_change_scheduled_at_crossover() { |
||||||
|
self.balance.actual = self.balance.target; |
||||||
|
self.update_gains(gain_scale); |
||||||
|
} |
||||||
|
|
||||||
|
if self.freq.is_change_scheduled_at_crossover() { |
||||||
|
self.freq.actual = self.freq.target; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let y = self.phase.sin() * self.gain.actual; |
||||||
|
|
||||||
|
StereoSample { |
||||||
|
left: self.gain_left * y, |
||||||
|
right: self.gain_right * y, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Waveform generator with multiple frequencies / waveforms
|
||||||
|
#[derive(Clone,Debug)] |
||||||
|
pub struct Instrument { |
||||||
|
/// Waveforms to combine to produce the final sound
|
||||||
|
pub waveforms: Vec<Oscillator>, |
||||||
|
/// Normalize the output to produce constant amplitude of 1.0 (instead of clipping)
|
||||||
|
normalize: bool, |
||||||
|
sample_rate : f32, |
||||||
|
master: Tween, |
||||||
|
} |
||||||
|
|
||||||
|
impl Instrument { |
||||||
|
pub fn new(waveforms: Vec<Oscillator>, sample_rate: f32) -> Self { |
||||||
|
let mut o = Self { |
||||||
|
waveforms, |
||||||
|
normalize: false, |
||||||
|
sample_rate, |
||||||
|
master: Tween { |
||||||
|
actual: 1.0, |
||||||
|
target: 1.0, |
||||||
|
step: None, |
||||||
|
min: 0.0, |
||||||
|
max: 1.0 |
||||||
|
} |
||||||
|
}; |
||||||
|
o |
||||||
|
} |
||||||
|
|
||||||
|
pub fn normalize(&mut self, normalize: bool) { |
||||||
|
self.normalize = normalize; |
||||||
|
|
||||||
|
// This is an artifact of how Oscillator works internally:
|
||||||
|
// The left/right gains are pre-computed and updated only when they change
|
||||||
|
if normalize { |
||||||
|
self.force_normalize(); |
||||||
|
} else { |
||||||
|
self.waveforms.iter_mut() |
||||||
|
.for_each(|item| item.update_gains(1.0)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_amp(&self) -> f32 { |
||||||
|
self.master.actual() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_amp(&mut self, amp : f32) { |
||||||
|
self.master.set_immediate(amp); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn fade_amp(&mut self, amp : f32, time: Duration) { |
||||||
|
self.master.fade(amp, time, self.sample_rate); |
||||||
|
} |
||||||
|
|
||||||
|
fn force_normalize(&mut self) { |
||||||
|
let gain_scale = 1.0 / self.waveforms.iter() |
||||||
|
.fold((0.0), |acc, item| acc + item.gain.actual); |
||||||
|
|
||||||
|
println!("Gain scale {}", gain_scale); |
||||||
|
self.waveforms.iter_mut() |
||||||
|
.for_each(|item| item.update_gains(gain_scale)); |
||||||
|
} |
||||||
|
|
||||||
|
/// Get a sample (left, right)
|
||||||
|
pub fn sample(&mut self) -> StereoSample { |
||||||
|
self.master.tick(); |
||||||
|
|
||||||
|
let gain_scaling = if self.normalize { |
||||||
|
1.0 / self.waveforms.iter() |
||||||
|
.fold((0.0), |acc, item| acc + item.gain.actual) |
||||||
|
} else { |
||||||
|
1.0 |
||||||
|
}; |
||||||
|
|
||||||
|
let (mut value, gains)= self.waveforms.iter_mut() |
||||||
|
.fold((StereoSample::default(), 0.0), |mut acc, item| { |
||||||
|
acc.0 += item.sample(gain_scaling); |
||||||
|
acc.1 += item.gain.actual; |
||||||
|
acc |
||||||
|
}); |
||||||
|
|
||||||
|
if self.normalize { |
||||||
|
value.left /= gains; |
||||||
|
value.right /= gains; |
||||||
|
} |
||||||
|
|
||||||
|
value.left = value.left.scale_gain(self.master.actual).clamp_(-1.0, 1.0); |
||||||
|
value.right = value.right.scale_gain(self.master.actual).clamp_(-1.0, 1.0); |
||||||
|
value.clip() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy)] |
||||||
|
pub struct StereoSample { |
||||||
|
pub left: f32, |
||||||
|
pub right: f32, |
||||||
|
} |
||||||
|
|
||||||
|
impl StereoSample { |
||||||
|
pub fn clip(self) -> Self { |
||||||
|
Self { |
||||||
|
left: self.left.clamp_(-1.0, 1.0), |
||||||
|
right: self.right.clamp_(-1.0, 1.0), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Add for StereoSample { |
||||||
|
type Output = Self; |
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output { |
||||||
|
Self { |
||||||
|
left: self.left + rhs.left, |
||||||
|
right: self.right + rhs.right, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Div<f32> for StereoSample { |
||||||
|
type Output = Self; |
||||||
|
|
||||||
|
fn div(self, rhs: f32) -> Self::Output { |
||||||
|
Self { |
||||||
|
left: self.left / rhs, |
||||||
|
right: self.right / rhs, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Mul<f32> for StereoSample { |
||||||
|
type Output = Self; |
||||||
|
|
||||||
|
fn mul(self, rhs: f32) -> Self::Output { |
||||||
|
Self { |
||||||
|
left: self.left * rhs, |
||||||
|
right: self.right * rhs, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl AddAssign<Self> for StereoSample { |
||||||
|
fn add_assign(&mut self, rhs: Self) { |
||||||
|
*self = *self + rhs |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl DivAssign<f32> for StereoSample { |
||||||
|
fn div_assign(&mut self, rhs: f32) { |
||||||
|
*self = *self / rhs |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl MulAssign<f32> for StereoSample { |
||||||
|
fn mul_assign(&mut self, rhs: f32) { |
||||||
|
*self = *self * rhs |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
mod beep; |
||||||
|
extern crate anyhow; |
||||||
|
extern crate cpal; |
||||||
|
|
||||||
|
fn main() -> Result<(), anyhow::Error> { |
||||||
|
beep::beep() |
||||||
|
} |
Loading…
Reference in new issue