├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE.txt
├── Linux
└── audiorecorder2
├── README.md
├── audiorecorder
├── audiorecorder.1
├── audiorecorder2-dev
├── README.md
├── audiorecorder2-osx.tgz
└── audiorecorder2
│ ├── Resources
│ ├── audiorecorder_large.png
│ ├── audiorecorder_play_large.gif
│ ├── audiorecorder_play_small.gif
│ ├── audiorecorder_small_1.png
│ ├── audiorecorder_small_2.png
│ └── audiorecorder_small_3.png
│ └── audiorecorder2.rb
├── current_interface.gif
├── history.md
├── macOS
└── audiorecorder2-osx.tgz
└── numbered_interface.png
/.gitignore:
--------------------------------------------------------------------------------
1 | *.shy
2 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at weevz@uw.edu. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) Andrew Weaver, 2017
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/Linux/audiorecorder2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/Linux/audiorecorder2
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # audiorecorder
2 |
3 | #### A free tool for the calibration and recording of analog audio signals
4 |
5 | ## Development information:
6 | For updates and history of development please see [this page](https://github.com/amiaopensource/audiorecorder/blob/master/history.md).
7 |
8 | ## Installation:
9 |
10 | __Audiorecorder2 Note:__ Audiorecorder2 can now be installed along side audiorecorder by adding the flag `--with-audiorecorder2` to the following homebrew install commands.
11 |
12 | audiorecorder can be installed via [Homebrew](https://brew.sh/) on macOS and Linux.
13 |
14 | __MacOS Installation__:
15 | Audiorecorder can be installed via Homebrew with the following commands:
16 |
17 | `brew tap amiaopensource/amiaos`
18 |
19 | `brew install audiorecorder`
20 |
21 | __Linux Installation__ (Tested in Ubuntu 16.04)
22 |
23 | The following division of commands seeks to install up-to-date versions of audiorecorder dependencies while avoiding conflicts.
24 |
25 | __Standard package manager commands__
26 |
27 | `sudo apt-get install sox`
28 |
29 | `sudo apt-get install libsdl2-2.0`
30 |
31 | Install current [MPV](https://mpv.io/installation/) ppa, then `sudo apt-get install mpv`
32 |
33 | __linuxbrew commands__
34 |
35 | `brew install dialog`
36 |
37 | If FFmpeg has already been installed with these options then skip next step.
38 |
39 | `brew install ffmpeg --with-freetype`
40 |
41 | sdl2 is necessary to build FFmpeg with FFplay, but removing it after build will avoid conflicts between other installations of sdl2.
42 |
43 | `brew uninstall --ignore-dependencies sdl2`
44 |
45 | `brew install --ignore-dependencies audiorecorder`
46 |
47 | ## Usage:
48 | Usage: [-p] passthrough mode, [-e] edit config, [-m] edit metadata for BWF insertion
49 |
50 | #### Initial setup:
51 | To set up audiorecorder, first run the command `audiorecorder -e`. This will open an interface where settings such as recording bit depth and sample rate can be selected. This is also where the option to embed BEXT metadata can be selected.
52 |
53 | To set the metadata that will be embedded in the BEXT chunk (if activated in the configuration menu) run the command `audiorecorder -m`. This will open an interface where the desired values can be entered.
54 |
55 | #### Explanation of Interface:
56 | 1: Peak volume meters (dB)
57 |
58 | 2: Audio spectrum - lines (from left) represent 1, 5, 10, 15, 20kHz respectively
59 |
60 | 3: Recording time
61 |
62 | 4: Spectrogram
63 |
64 | 5: Audio vecorscope
65 |
66 | 6: Graph of peak volume values (dB) from -30dB to 0dB. Colored area represents -5dB to 0dB.
67 |
68 |
69 |
70 | #### Preview:
71 | Running `audiorecorder -p` will open the preview window. This window can be closed with the escape key. This allows you to check your settings and playback machine calibration using the audiorecorder interface without creating a file. It is recommended to use this mode before every recording. Once you are satisfied that everything is calibrated appropriately, move on to record mode.
72 |
73 | #### Record:
74 | Running the command `audiorecorder` will start record mode. You will be prompted for the name of the file created. __Wait until the audiorecorder interface opens__, and then press play on your playback machine. During recording do not resize the window, as this can cause problems with the audio buffer. To stop recording press the escape key.
75 |
76 | Once recording is complete, audiorecorder will process the file, and then an interface will open showing the waveform of the recorded file, as well as giving options to 'preview' and 'trim' the file.
77 |
78 | Press 'Preview' to hear the file you recorded. To trim file, enter the amount (in seconds) to trim from the start and end of the file and press 'Trim'. If 'Start Trim' is left blank, auto-trim will be applied to start of file. If no trim at start is desired enter '0'. After trimming, a preview window will open for your new file. Trim can be run as many times as is necessary. Once you are done, press 'Finish' to finalize and quit. It is at this point that BEXT metadata will be embedded if that option has been selected.
79 |
80 | ## Huge thanks to all contributors to audiorecorder!
81 |
82 | #### Project Maintainers are:
83 | Andrew Weaver (@privatezero)
84 |
85 | Ashley Blewer (@ablwr)
86 |
87 | #### Contributors to date:
88 | privatezero (Andrew Weaver), retokromer (Reto Kromer), dericed (Dave Rice), todrobbins (Tod Robbins), ablwr (Ashley Blewer)
89 |
90 | Special thanks to Matt Boyd at the University of Washington for extensive testing assistance!
91 |
92 | ## License
93 |
94 | The audiorecorder script is covered under a [BSD 3-clause license](https://github.com/amiaopensource/audiorecorder/blob/master/LICENSE.txt)
95 |
96 | 
All documentation for audiorecorder is licensed under a Creative Commons Attribution 4.0 International License.
97 |
--------------------------------------------------------------------------------
/audiorecorder:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # audiorecorder
4 |
5 | VERSION=$(TMP=$(brew info audiorecorder | grep ".*\*$" | grep -Eo "/audiorecorder/.* \(") ; echo ${TMP:15:(${#TMP}-17)})
6 | config="${HOME}/.$(basename "${0}").conf"
7 | bwf_config="${HOME}/.$(basename "${0}")_BWF.conf"
8 | # setup config file if doesn't exist
9 | if ! [ -e "${config}" ] ; then
10 | sample_rate='96 kHz'
11 | bit_depth='24 bit'
12 | channel_layout='1 and 2'
13 | bwf='0'
14 | {
15 | echo "#Please input choices between the quotes from the options supplied"
16 | echo ""
17 | echo "#Enter output directory for digitized files"
18 | echo "output=\"${output}\""
19 | echo ""
20 | echo "#Sample Rate Choices: 44.1 kHz, 48 kHz, 96 kHz"
21 | echo "sample_rate=\"${sample_rate}\""
22 | echo "#Bit Depth Choices: 16 bit, 24 bit"
23 | echo "bit_depth=\"${bit_depth}\""
24 | echo "#Channel Layout Choices: 1, 2, 1 and 2"
25 | echo "channel_layout=\"${channel_layout}\""
26 | echo "#BWF Choices 0, 1 (0 for off 1 for on)"
27 | echo "bwf=\"${bwf}\""
28 | } > "${config}"
29 | fi
30 | # setup metadata config file if doesn't exist
31 | if ! [ -e "${bwf_config}" ] ; then
32 | {
33 | echo "#Enter originator information betwen the quotes"
34 | echo "originator=\"${originator}\""
35 | echo ""
36 | echo "#Enter Coding History information betwen the quotes"
37 | echo "coding_history=\"${coding_history}\""
38 | } > "${bwf_config}"
39 | fi
40 |
41 | touch ~/.config/mpv/input.conf
42 | . "${config}"
43 | . "${bwf_config}"
44 | #Set mpv to quit with same key as ffplay
45 | echo "ESC quit" > ~/.config/mpv/input.conf
46 |
47 | _usage(){
48 | cat < in 10/2003, modified in 12/2003 (including
77 | # a code snippet contributed by Tor Sigurdsson), 08/2004 and 12/2004.
78 | bundlepath="Pashua.app/Contents/MacOS/Pashua"
79 | mypath=$(dirname "${0}")
80 | for searchpath in "$mypath/Pashua" "$mypath/$bundlepath" "./$bundlepath" \
81 | "/Applications/$bundlepath" "$HOME/Applications/$bundlepath"
82 | do
83 | if [ -f "${searchpath}" -a -x "${searchpath}" ] ; then
84 | pashuapath=${searchpath}
85 | break
86 | fi
87 | done
88 | if [ ! "${pashuapath}" ] && [[ "$(uname -s)" = "Darwin" ]]; then
89 | echo "Error: Pashua was not found. Proceeding with Nano. Please install Pashua a more functional interface."
90 | GUI_TEST=1
91 | fi
92 |
93 | #Setup differences for systems
94 | if [[ "$(uname -s)" = "Darwin" ]] ; then
95 | FONTPATH='/Library/Fonts/Andale Mono.ttf'
96 | else
97 | GUI_TEST=1
98 | FONTPATH='/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf'
99 | fi
100 |
101 | _lookup_sample_rate(){
102 | case "${1}" in
103 | "44.1 kHz")
104 | SAMPLE_RATE_NUMERIC="44100"
105 | ;;
106 | "48 kHz")
107 | SAMPLE_RATE_NUMERIC="48000"
108 | ;;
109 | "96 kHz")
110 | SAMPLE_RATE_NUMERIC="96000"
111 | ;;
112 | esac
113 | }
114 |
115 | _lookup_bit_depth(){
116 | case "${1}" in
117 | "16 bit")
118 | CODEC="pcm_s16le"
119 | ;;
120 | "24 bit")
121 | CODEC="pcm_s24le"
122 | ;;
123 | esac
124 | }
125 |
126 | _lookup_channel_layout(){
127 | case "${1}" in
128 | "1")
129 | CHANNEL_LAYOUT="-channel_layout mono" && SOXCHANNELS="1"
130 | ;;
131 | "2")
132 | CHANNEL_LAYOUT="-channel_layout mono" && SOXCHANNELS="2"
133 | ;;
134 | "1 and 2")
135 | CHANNEL_LAYOUT="-channel_layout stereo" && SOXCHANNELS="1 2"
136 | ;;
137 | "3 and 4")
138 | CHANNEL_LAYOUT="-channel_layout stereo" && SOXCHANNELS="3 4"
139 | ;;
140 | esac
141 | }
142 |
143 | _get_ITEM_ID(){
144 | echo "Please Input Item ID or type Q to exit"
145 | read ITEM_ID
146 | if [[ "${ITEM_ID}" = [Qq] ]] ; then
147 | echo "Goodbye!"
148 | exit 0
149 | fi
150 | if [ -f "${output}/${ITEM_ID}.wav" ] ; then
151 | echo "A file with that name already exists!"
152 | _get_ITEM_ID
153 | fi
154 | }
155 |
156 | _destination_check(){
157 | if [ -z "${output}" ] || [ ! -d "${output}" ] ; then
158 | echo "Please enter a valid output directory"
159 | read -r output
160 | _destination_check
161 | fi
162 | }
163 |
164 | _metadata_gui(){
165 | gui_conf="
166 | # Set transparency: 0 is transparent, 1 is opaque
167 | *.transparency=0.95
168 | # Set window title
169 | *.title = Edit Metadata Values
170 | # intro text
171 | intro.width = 300
172 | intro.type = text
173 | intro.text = Hello
174 | #Originator
175 | originator.type = textfield
176 | originator.label = Enter Originator
177 | originator.default = "${originator}"
178 | #Coding History
179 | coding_history.type = textbox
180 | coding_history.label = Enter Coding History
181 | coding_history.default = "${coding_history}"
182 | cb.type = cancelbutton
183 | cb.label = Cancel
184 | "
185 |
186 | if ! [ "${GUI_TEST}" = 1 ] ; then
187 | pashua_configfile=$(/usr/bin/mktemp /tmp/pashua_XXXXXXXXX)
188 | echo "${gui_conf}" > "${pashua_configfile}"
189 | pashua_run
190 | rm "${pashua_configfile}"
191 | else
192 | nano "${bwf_config}"
193 | . "${bwf_config}"
194 | fi
195 | }
196 |
197 | _master_gui(){
198 | gui_conf="
199 | # Set transparency: 0 is transparent, 1 is opaque
200 | *.transparency=0.95
201 | # Set window title
202 | *.title = Welcome to Audio Recorder!
203 | # intro text
204 | intro.width = 300
205 | intro.type = text
206 | intro.text = Hello
207 | #Output Location
208 | output.type = openbrowser
209 | output.label = Output Location
210 | output.default = "${output}"
211 | #Sample Rate
212 | sample_rate.type = radiobutton
213 | sample_rate.label = Select Sample Rate
214 | sample_rate.option = 44.1 kHz
215 | sample_rate.option = 48 kHz
216 | sample_rate.option = 96 kHz
217 | sample_rate.default = "${sample_rate}"
218 | #Bit Depth
219 | bit_depth.type = radiobutton
220 | bit_depth.label = Select Bit Depth
221 | bit_depth.option = 16 bit
222 | bit_depth.option = 24 bit
223 | bit_depth.default = "${bit_depth}"
224 | #Channel Layout
225 | channel_layout.type = radiobutton
226 | channel_layout.label = Select Input Channel(s)
227 | channel_layout.option = 1
228 | channel_layout.option = 2
229 | channel_layout.option = 1 and 2
230 | channel_layout.option = 3 and 4
231 | channel_layout.default = "${channel_layout}"
232 | #Enable BWF
233 | bwf.type = checkbox
234 | bwf.label = Embed BWF Metadata
235 | bwf.default = "${bwf}"
236 | #Cancel Button
237 | cb.type = cancelbutton
238 | cb.label = Cancel
239 | "
240 |
241 | if ! [ "${GUI_TEST}" = 1 ] ; then
242 | pashua_configfile=$(/usr/bin/mktemp /tmp/pashua_XXXXXXXXX)
243 | echo "${gui_conf}" > "${pashua_configfile}"
244 | pashua_run
245 | rm "${pashua_configfile}"
246 | else
247 | nano "${config}"
248 | . "$config"
249 | fi
250 | }
251 |
252 | _post_digitization_gui(){
253 | post_gui_conf="
254 | # Set transparency: 0 is transparent, 1 is opaque
255 | *.transparency=0.95
256 | # Set window title
257 | *.title = Press ok to exit
258 | # intro text
259 | intro.width = 300
260 | intro.type = text
261 | intro.text = Please Select Post-digitization Options
262 | intro.x = 150
263 | intro.y = 500
264 | #Waveform
265 | waveform.type = image
266 | waveform.path = AUDIORECORDERTEMP.tiff
267 | waveform.x = 5
268 | waveform.y = 350
269 | #Preview
270 | preview.type = button
271 | preview.label = Preview
272 | preview.x = 10
273 | preview.y = 320
274 | #Trim
275 | trim.type = button
276 | trim.label = Trim
277 | trim.x = 150
278 | trim.y = 320
279 | #Instructions
280 | instructions.type = text
281 | instructions.width = 500
282 | instructions.default = Press 'Preview' to hear the file you recorded.[return][return]To trim file, enter the amount (in seconds) to trim from the start and end of the file and press 'Trim'.[return][return]If 'Start Trim' is left blank, auto-trim will be applied to start of file. If no trim at start is desired enter '0'. After trimming, a preview window will open for your new file. Trim can be run as many times as is neccessary.[return][return]Press 'Finish' to quit.
283 | instructions.x = 10
284 | instructions.y = 150
285 | #Start Trim Length
286 | StartTrimLength.type = textfield
287 | StartTrimLength.label = Start Trim
288 | StartTrimLength.width = 100
289 | StartTrimLength.x = 10
290 | StartTrimLength.y = 60
291 | #End Trim Length
292 | EndTrimLength.type = textfield
293 | EndTrimLength.label = End Trim
294 | EndTrimLength.width = 100
295 | EndTrimLength.x = 10
296 | EndTrimLength.y = 5
297 | exit.type = defaultbutton
298 | exit.label = Finish
299 | "
300 |
301 | if ! [ "${GUI_TEST}" = 1 ] ; then
302 | pashua_configfile=$(/usr/bin/mktemp /tmp/pashua_XXXXXXXXX)
303 | echo "${post_gui_conf}" > "${pashua_configfile}"
304 | pashua_run
305 | rm "${pashua_configfile}"
306 | else
307 | unset preview
308 | unset trim
309 | post_dig_opt=(preview trim exit)
310 | post_dig=$(dialog --title "Select Action" --radiolist "Click or use arrow keys and space bar to select" 15 60 4 "${post_dig_opt[0]}" "file" ON "${post_dig_opt[1]}" "file" OFF "${post_dig_opt[2]}" "audiorecorder" OFF 3>&1 1>&2 2>&3 3>&-)
311 | if [ "${post_dig}" = "trim" ] ; then
312 | StartTrimLength=$(dialog --title "Start Trim Length" --inputbox "Enter seconds to trim from start of file. Leave blank for auto. Enter 0 if no trimming is desired." 8 50 3>&1 1>&2 2>&3 3>&-)
313 | EndTrimLength=$(dialog --title "End Trim Length" --inputbox "Enter seconds to trim from end of file. Leave blank if no trimming is desired." 8 50 3>&1 1>&2 2>&3 3>&-)
314 | fi
315 | case "${post_dig}" in
316 | "preview")
317 | preview="1"
318 | ;;
319 | "trim")
320 | trim="1"
321 | ;;
322 | "exit")
323 | clear
324 | ;;
325 | esac
326 | fi
327 |
328 | if [ "${preview}" = "1" ] ; then
329 | _preview_file && _post_digitization_gui
330 | fi
331 |
332 | if [ "${trim}" = "1" ] ; then
333 | _trim_file && _post_digitization_gui
334 | fi
335 | }
336 |
337 | _embed_bext(){
338 | echo "Preparing to embed metadata in ${BEXT_TARGET}"
339 | echo ""
340 | if (("${#ITEM_ID}" > 32)) ; then
341 | orig_ref="See description for Identifiers"
342 | else
343 | orig_ref="${ITEM_ID}"
344 | fi
345 |
346 | bwfmetaedit --reject-overwrite --Description="${ITEM_ID}".wav --Originator="${originator}" --OriginatorReference="${orig_ref}" --History="${coding_history}" --IARL="${originator}" --MD5-Embed --OriginationDate=$(date "+%Y-%m-%d") --OriginationTime=$(date "+%H:%M:%S") "${BEXT_TARGET}"
347 | }
348 |
349 | pashua_run() {
350 | # Wrapper function for interfacing to Pashua. Written by Carsten
351 | # Bluem in 10/2003, modified in 12/2003 (including
352 | # a code snippet contributed by Tor Sigurdsson), 08/2004 and 12/2004.
353 | # Write config file
354 |
355 | # Find Pashua binary. We do search both . and dirname "$0"
356 | # , as in a doubleclickable application, cwd is /
357 | # BTW, all these quotes below are necessary to handle paths
358 | # containing spaces.
359 |
360 | # Get result
361 | result=$("$pashuapath" ${pashua_configfile} | sed 's/ /;;;/g')
362 |
363 | # Parse result
364 | for line in $result ; do
365 | key=$(echo ${line} | sed 's/^\([^=]*\)=.*$/\1/')
366 | value=$(echo ${line} | sed 's/^[^=]*=\(.*\)$/\1/' | sed 's/;;;/ /g')
367 | varname=${key}
368 | varvalue="${value}"
369 | eval $varname='$varvalue'
370 | done
371 | } # pashua_run()
372 |
373 | if [ "${runtype}" = "edit" ] ; then
374 | _master_gui
375 |
376 | {
377 | echo "#Please input choices between the quotes from the options supplied"
378 | echo ""
379 | echo "#Enter output directory for digitized files"
380 | echo "output=\"${output}\""
381 | echo ""
382 | echo "#Sample Rate Choices: 44.1 kHz, 48 kHz, 96 kHz"
383 | echo "sample_rate=\"${sample_rate}\""
384 | echo "#Bit Depth Choices: 16 bit, 24 bit"
385 | echo "bit_depth=\"${bit_depth}\""
386 | echo "#Channel Layout Choices: 1, 2, 1 and 2"
387 | echo "channel_layout=\"${channel_layout}\""
388 | echo "#BWF Choices 0, 1 (0 for off 1 for on)"
389 | echo "bwf=\"${bwf}\""
390 | } > "${config}"
391 | echo "Audiorecorder settings updated."
392 | exit 0
393 | fi
394 | if [ "${runtype}" = "metadata" ] ; then
395 | _metadata_gui
396 | {
397 | echo "#Enter originator information betwen the quotes"
398 | echo "originator=\"${originator}\""
399 | echo ""
400 | echo "#Enter Coding History information betwen the quotes"
401 | echo "coding_history=\"${coding_history}\""
402 | } > "${bwf_config}"
403 | echo "BWF settings updated."
404 | exit 0
405 | fi
406 |
407 | #Verify and configure
408 | if [ -n "${sample_rate}" ] ; then
409 | _lookup_sample_rate "${sample_rate}"
410 | else
411 | echo "No Sample Rate Specified. Setting to 96kH."
412 | SAMPLE_RATE_NUMERIC="96000"
413 | fi
414 | if [ -n "${bit_depth}" ] ; then
415 | _lookup_bit_depth "${bit_depth}"
416 | else
417 | echo "No Bit Depth Specified. Setting to 24."
418 | CODEC="pcm_s24le"
419 | fi
420 | if [ -n "${channel_layout}" ] ; then
421 | _lookup_channel_layout "${channel_layout}"
422 | else
423 | echo "No Channel Layout Specified. Setting Input to Channels 1 and 2"
424 | channel_layout="1 and 2"
425 | fi
426 |
427 | FILTER_CHAIN="asplit=6[out1][a][b][c][d][e],\
428 | [e]showvolume=w=700:c=0xFFff0000:r=30[e1],\
429 | [a]showfreqs=mode=bar:cmode=separate:size=300x300:colors=magenta|yellow[a1],\
430 | [a1]drawbox=12:0:3:300:white@0.2[a2],[a2]drawbox=66:0:3:300:white@0.2[a3],[a3]drawbox=135:0:3:300:white@0.2[a4],[a4]drawbox=202:0:3:300:white@0.2[a5],[a5]drawbox=271:0:3:300:white@0.2[aa],\
431 | [b]avectorscope=s=300x300:r=30:zoom=5[b1],\
432 | [b1]drawgrid=x=150:y=150:c=white@0.3[bb],\
433 | [c]showspectrum=s=400x600:slide=scroll:mode=combined:color=rainbow:scale=lin:saturation=4[cc],\
434 | [d]astats=metadata=1:reset=1,adrawgraph=lavfi.astats.Overall.Peak_level:max=0:min=-30.0:size=700x256:bg=Black[dd],\
435 | [dd]drawbox=0:0:700:42:hotpink@0.2:t=42[ddd],\
436 | [aa][bb]vstack[aabb],[aabb][cc]hstack[aabbcc],[aabbcc][ddd]vstack[aabbccdd],[e1][aabbccdd]vstack[z],\
437 | [z]drawtext=fontfile="${FONTPATH}": text='%{pts \\: hms}':x=460: y=50:fontcolor=white:fontsize=30:box=1:boxcolor=0x00000000@1[fps],[fps]fps=fps=30[out0]"
438 |
439 | # BEXT mode
440 | if [ "${runtype}" = "bext" ] ; then
441 | ITEM_ID=$(basename "${2}" | cut -d'.' -f1)
442 | BEXT_TARGET="${2}"
443 | _embed_bext
444 | exit 0
445 | fi
446 |
447 | # Passthrough mode
448 | if [ "${runtype}" = "passthrough" ] ; then
449 | rec -r "${SAMPLE_RATE_NUMERIC}" -b 32 -L -e signed-integer --buffer 500000 -p remix ${SOXCHANNELS} | ffmpeg ${CHANNEL_LAYOUT} -i - -f wav -c:a pcm_s16le -ar 44100 - |\
450 | ffplay -window_title "Monitoring Channel(s): ${channel_layout}" -f lavfi "amovie='pipe\:0',${FILTER_CHAIN}" 2> /dev/null
451 | stty sane
452 | exit
453 | fi
454 |
455 | _destination_check
456 |
457 | # Record Mode
458 | _get_ITEM_ID
459 |
460 | if [ -e AUDIORECORDERTEMP.wav ] ; then
461 | rm -r AUDIORECORDERTEMP.wav
462 | fi
463 |
464 | #ASTATS_OUT=$(mktemp /tmp/temp.XXXX)
465 | rec -r "${SAMPLE_RATE_NUMERIC}" -b 32 -L -e signed-integer --buffer 2000000 -p remix ${SOXCHANNELS} | ffmpeg ${CHANNEL_LAYOUT} -i - -f wav -c:a "${CODEC}" -ar "${SAMPLE_RATE_NUMERIC}" -metadata comment="" -y -rf64 auto AUDIORECORDERTEMP.wav -f wav -c:a pcm_s16le -ar 44100 - |\
466 | ffplay -window_title "Currently Recording Channel(s): ${channel_layout}" -f lavfi "amovie='pipe\:0',${FILTER_CHAIN}" 2> /dev/null
467 | # Cleanup
468 | stty sane
469 |
470 | ##COMMENTING OUT FOR NOW DUE TO LACK OF ACCURACY###
471 | # Post Recording Stats
472 | #PEAK_COUNT=$(cat "${ASTATS_OUT}" | tail -n -8 | grep "Peak count" | cut -d':' -f2 | cut -c 2- | cut -d'.' -f1)
473 |
474 | #if [ "${PEAK_COUNT}" -gt "4" ] ; then
475 | # echo -e "\033[101mWarning: There are $((${PEAK_COUNT} - 2)) samples with peaked levels in this recording.\033[0m"
476 | #fi
477 |
478 | #ASTATS=$(cat "${ASTATS_OUT}" | tail -n -8 | cut -d']' -f2 | cut -c 2- | head -n 4)
479 | #echo -e "\033[1;32mLevels from recorded file are:\033[0m"
480 | #echo -e "\033[1;32m${ASTATS}\033[0m"
481 |
482 | #Post Record Functions
483 | PRETRIM="${output}"/"${ITEM_ID}"_untrimmed.wav
484 | FINALOUTPUT="${output}"/"${ITEM_ID}".wav
485 | _preview_file(){
486 | if [ -z "${TRIMCHECK}" ] ; then
487 | mpv --force-window --no-terminal --keep-open=yes --title="Preview" --geometry=620x620 -lavfi-complex "[aid1]asplit=3[ao][a][b],[a]showwaves=600x240:n=1[a1],[a1]drawbox=0:0:600:240:t=120[a2],[b]showwaves=600x240:mode=cline:colors=0x00FFFF:split_channels=1[b2],[a2][b2]overlay[vo]" "${FINALOUTPUT}"
488 | else
489 | mpv --force-window --no-terminal --keep-open=yes --title="Preview" --geometry=620x620 -lavfi-complex "[aid1]asplit=3[ao][a][b],[a]showwaves=600x240:n=1[a1],[a1]drawbox=0:0:600:240:t=120[a2],[b]showwaves=600x240:mode=cline:colors=0x00FFFF:split_channels=1[b2],[a2][b2]overlay[vo]" "${PRETRIM}"
490 | fi
491 | }
492 |
493 | _set_up_trim(){
494 | if [ -n "${EndTrimLength}" ] ; then
495 | FILELENGTH=$(ffprobe "${1}" 2>&1 | grep Duration | tr -d ' ' | cut -d',' -f1 | cut -d':' -f2-)
496 | FILELENGTH_NORMALIZED=$(echo "${FILELENGTH}" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
497 | ENDTRIM=$(echo "${FILELENGTH_NORMALIZED}" - "${EndTrimLength}" | bc)
498 | if [ -n "${StartTrimLength}" ] && [ -n "${EndTrimLength}" ] ; then
499 | ENDTRIM=$(echo "${FILELENGTH_NORMALIZED}" - "${EndTrimLength}" - "${StartTrimLength}" | bc)
500 | fi
501 | ENDTRIMOPT="-t ${ENDTRIM}"
502 | fi
503 | if [ -n "${StartTrimLength}" ] ; then
504 | STARTTRIMOPT="-ss ${StartTrimLength}"
505 | fi
506 | }
507 |
508 | _trim_file(){
509 | if [ -n "${StartTrimLength}" ] && ! [[ "${StartTrimLength}" =~ ^[+]?[0-9]+\.?[0-9]*$ ]] ; then
510 | echo "Please use only (positive) numbers for the trim length"
511 | elif [ -n "${EndTrimLength}" ] && ! [[ "${EndTrimLength}" =~ ^[+]?[0-9]+\.?[0-9]*$ ]] ; then
512 | echo "Please use only (positive) numbers for the trim length"
513 | else
514 | if [[ -z "${TRIMCHECK}" ]] ; then
515 | _set_up_trim "${FINALOUTPUT}"
516 | mv "${FINALOUTPUT}" "${PRETRIM}"
517 | else
518 | _set_up_trim "${PRETRIM}"
519 | fi
520 | if [[ -z "${StartTrimLength}" ]] ; then
521 | if [ -n "${EndTrimLength}" ] ; then
522 | ffmpeg -i "${PRETRIM}" -af silenceremove=start_threshold=-57dB:start_duration=1:start_periods=1 -f wav -c:a "${CODEC}" -ar "${SAMPLE_RATE_NUMERIC}" -rf64 auto -y INTERMEDIATE.wav
523 | _set_up_trim INTERMEDIATE.wav
524 | ffmpeg -i INTERMEDIATE.wav -c copy -t "${ENDTRIM}" -rf64 auto -y "${FINALOUTPUT}"
525 | rm INTERMEDIATE.wav
526 | else
527 | ffmpeg -i "${PRETRIM}" -af silenceremove=start_threshold=-57dB:start_duration=1:start_periods=1 -f wav -c:a "${CODEC}" -ar "${SAMPLE_RATE_NUMERIC}" -rf64 auto -y "${FINALOUTPUT}"
528 | fi
529 | else
530 | ffmpeg ${STARTTRIMOPT} -i "${PRETRIM}" -c copy -rf64 auto ${ENDTRIMOPT} -y "${FINALOUTPUT}"
531 | fi
532 | TRIMCHECK='1'
533 | mpv --force-window --no-terminal --keep-open=yes --title="Preview Trim" --geometry=620x620 -lavfi-complex "[aid1]asplit=3[ao][a][b],[a]showwaves=600x240:n=1[a1],[a1]drawbox=0:0:600:240:t=120[a2],[b]showwaves=600x240:mode=cline:colors=0x00FFFF:split_channels=1[b2],[a2][b2]overlay[vo]" "${FINALOUTPUT}"
534 | fi
535 | unset STARTTRIMOPT
536 | unset ENDTRIMOPT
537 | }
538 |
539 | # Cleans up and loads post digitization option GUI
540 | ffmpeg -i AUDIORECORDERTEMP.wav -lavfi showwavespic=split_channels=1:s=500x150:colors=blue -y AUDIORECORDERTEMP.tiff -c copy "${FINALOUTPUT}"
541 | rm AUDIORECORDERTEMP.wav && _post_digitization_gui
542 |
543 | # Embed metadata in BEXT
544 | if [ "${bwf}" = "1" ] ; then
545 | BEXT_TARGET="${FINALOUTPUT}"
546 | _embed_bext
547 | fi
548 | rm AUDIORECORDERTEMP.tiff
549 |
550 | #Cascadia Now!
551 |
--------------------------------------------------------------------------------
/audiorecorder.1:
--------------------------------------------------------------------------------
1 | .TH audiorecorder 1 "github.com/amiaopensource/audiorecorder" "2019-05-21" "AMIA Open Source"
2 | .\" Turn off justification for nroff.
3 | .if n .ad l
4 | .\" Turn off hyphenation.
5 | .nh
6 | .SH NAME
7 | audiorecorder - Tool for calibration and recording of analog audio sources
8 | .SH SYNOPSIS
9 | \fBaudiorecorder\fR [\fB-e\fR | \fB-p\fR | \fB-m\fR | \fB-b\fR | \fB-h\fR]
10 | .SH OPTIONS
11 | .TP
12 | .B -e
13 | edit config
14 | .TP
15 | .B -p
16 | passthrough mode
17 | .TP
18 | .B -m
19 | edit metadata to be used in BWF creation
20 | .TP
21 | .B -b
22 | embed BEXT chunk (BWF metadata) in target file
23 | .TP
24 | .B -h
25 | display a help message
26 | .SH LICENSE
27 | .TP
28 | The audiorecorder script is covered under a BSD 3-clause license.
29 | .TP
30 | All documentation for audiorecorder is licensed under a Creative Commons Attribution 4.0 International License.
31 |
--------------------------------------------------------------------------------
/audiorecorder2-dev/README.md:
--------------------------------------------------------------------------------
1 | # audiorecorder2
2 |
3 | ## initial sandbox for audiorecorder2 GUI build using Shoes
4 |
5 | Currently does not include absolute paths for dependencies that are required for macOS functionality. Test build is operational in Linux - GUI can be opened (but isn't functional) on macOS
6 |
--------------------------------------------------------------------------------
/audiorecorder2-dev/audiorecorder2-osx.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/audiorecorder2-dev/audiorecorder2-osx.tgz
--------------------------------------------------------------------------------
/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_large.png
--------------------------------------------------------------------------------
/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_play_large.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_play_large.gif
--------------------------------------------------------------------------------
/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_play_small.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_play_small.gif
--------------------------------------------------------------------------------
/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_small_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_small_1.png
--------------------------------------------------------------------------------
/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_small_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_small_2.png
--------------------------------------------------------------------------------
/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_small_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/audiorecorder2-dev/audiorecorder2/Resources/audiorecorder_small_3.png
--------------------------------------------------------------------------------
/audiorecorder2-dev/audiorecorder2/audiorecorder2.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 | require 'json'
3 |
4 | # Recording Variables
5 | if RUBY_PLATFORM.include?('linux')
6 | Drawfontpath = '/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf'
7 | Soxpath = 'rec'
8 | Ffmpegpath = 'ffmpeg'
9 | Ffplaypath = 'ffplay'
10 | Ffprobepath = 'ffprobe'
11 | Bwfmetaeditpath = 'bwfmetaedit'
12 | Mpvpath = 'mpv'
13 | elsif RUBY_PLATFORM.include?('darwin')
14 | Drawfontpath = '/Library/Fonts/Andale Mono.ttf'
15 | Soxpath = '/usr/local/bin/rec'
16 | Ffmpegpath = '/usr/local/bin/ffmpeg'
17 | Ffplaypath = '/usr/local/bin/ffplay'
18 | Ffprobepath = '/usr/local/bin/ffprobe'
19 | Bwfmetaeditpath = '/usr/local/bin/bwfmetaedit'
20 | Mpvpath = '/usr/local/bin/mpv'
21 | else
22 | Drawfontpath = 'some windows path'
23 | end
24 |
25 | # Check FFmpeg version for filter options
26 |
27 | if system('#{Ffmpegpath} -version | grep "ffmpeg version 4.0.0\|ffmpeg version 4.0.1\|ffmpeg version 4.0.2"')
28 | Avectorscopefilter = 'avectorscope=s=300x300:r=30:zoom=5:mirror=0'
29 | else
30 | Avectorscopefilter = 'avectorscope=s=300x300:r=30:zoom=5'
31 | end
32 |
33 | FILTER_CHAIN = "asplit=6[out1][a][b][c][d][e],\
34 | [e]showvolume=w=700:c=0xFFff0000:r=30[e1],\
35 | [a]showfreqs=mode=bar:cmode=separate:size=300x300:colors=magenta|yellow[a1],\
36 | [a1]drawbox=12:0:3:300:white@0.2[a2],[a2]drawbox=66:0:3:300:white@0.2[a3],[a3]drawbox=135:0:3:300:white@0.2[a4],[a4]drawbox=202:0:3:300:white@0.2[a5],[a5]drawbox=271:0:3:300:white@0.2[aa],\
37 | [b]#{Avectorscopefilter}[b1],\
38 | [b1]drawgrid=x=150:y=150:c=white@0.3[bb],\
39 | [c]showspectrum=s=400x600:slide=scroll:mode=combined:color=rainbow:scale=lin:saturation=4[cc],\
40 | [d]astats=metadata=1:reset=1,adrawgraph=lavfi.astats.Overall.Peak_level:max=0:min=-30.0:size=700x256:bg=Black[dd],\
41 | [dd]drawbox=0:0:700:42:hotpink@0.2:t=42[ddd],\
42 | [aa][bb]vstack[aabb],[aabb][cc]hstack[aabbcc],[aabbcc][ddd]vstack[aabbccdd],[e1][aabbccdd]vstack[z],\
43 | [z]drawtext=fontfile=#{Drawfontpath}: text='%{pts \\: hms}':x=460: y=50:fontcolor=white:fontsize=30:box=1:boxcolor=0x00000000@1[fps],[fps]fps=fps=30[out0]"
44 |
45 | # Set Configuration
46 | sox_channels = '1 2'
47 | ffmpeg_channels = 'stereo'
48 | $codec_choice = 'pcm_s24le'
49 | $soxbuffer = '50000'
50 | $sample_rate_choice = '96000'
51 | $filename = ''
52 |
53 | # Load options from config file
54 | configuration_file = File.expand_path('~/.audiorecorder2.conf')
55 | if ! File.exist?(configuration_file)
56 | config_options = "destination:\nsamplerate:\nchannels:\ncodec:\norig:\nhist:\nbext:"
57 | File.write(configuration_file, config_options)
58 | end
59 | config = YAML::load_file(configuration_file)
60 | $outputdir = config['destination']
61 | $sample_rate_choice = config['samplerate']
62 | sox_channels = config['channels']
63 | $codec_choice = config['codec']
64 | $originator = config['orig']
65 | $history = config['hist']
66 | $embedbext = config['bext']
67 |
68 | #BWF Metaedit Function
69 | def EmbedBEXT(targetfile)
70 | moddatetime = File.mtime(targetfile)
71 | moddate = moddatetime.strftime("%Y-%m-%d")
72 | modtime = moddatetime.strftime("%H:%M:%S")
73 |
74 | #Get Input Name for Description and OriginatorReference
75 | file_name = File.basename(targetfile)
76 | originatorreference = File.basename(targetfile, '.wav')
77 | if originatorreference.length > 32
78 | originatorreference = "See Description for Identifiers"
79 | end
80 | bwfcommand = Bwfmetaeditpath + ' --reject-overwrite ' + '--Description=' + "'" + file_name + "'" + ' --Originator=' + "'" + $originator + "'" + ' --History=' + "'" + $history + "'" + ' --OriginatorReference=' + "'" + originatorreference + "'" + ' --OriginationDate=' + moddate + ' --OriginationTime=' + modtime + ' --MD5-Embed ' + "'" + targetfile + "'"
81 | system(bwfcommand)
82 | end
83 |
84 | #Function for adjusting buffer
85 | def BufferCheck(sr)
86 | if sr == '96000'
87 | $soxbuffer = '50000'
88 | elsif sr == '48000'
89 | $soxbuffer = '25000'
90 | elsif sr == '44100'
91 | $soxbuffer = '23000'
92 | end
93 | end
94 |
95 | # GUI App
96 | Shoes.app(title: "AudioRecorder2", width: 600, height: 625) do
97 | style Shoes::Para, font: "Helvetica"
98 | background aliceblue
99 | @logo = image("Resources/audiorecorder_small_1.png", left: 160)
100 | animate(10) do |frame|
101 | if frame.to_i.even?
102 | @logo.path = "Resources/audiorecorder_small_3.png"
103 | else
104 | @logo.path = "Resources/audiorecorder_small_2.png"
105 | end
106 | end
107 |
108 | def PostRecord(targetfile)
109 | window(title: "Post-Record Options", width: 600, height: 560) do
110 | style Shoes::Para, font: "Helvetica"
111 | background aliceblue
112 | trimcheck = nil
113 | @pretrim = $outputdir + '/' + File.basename(targetfile, File.extname(targetfile)) + '_untrimmed' + '.wav'
114 | @finaloutput = targetfile
115 | @trimtemp = $outputdir + '/' + 'trim_tempfile.wav'
116 | stack margin: 15 do
117 | border gainsboro, strokewidth: 6
118 | waveform = image($waveform_pic)
119 | end
120 | @start_trim = nil
121 | @end_trim_length = nil
122 |
123 | def SetUpTrim(input)
124 | ffprobe_command = Ffprobepath + ' -print_format json -show_streams ' + "'" + input + "'"
125 | $ffprobeout = JSON.parse(`#{ffprobe_command}`)
126 | @duration_json = $ffprobeout['streams'][0]['duration']
127 | @duration =@duration_json.to_f
128 | if ! @end_trim_length.nil? && @start_trim_length != "AUTO"
129 | $end_trim_opt = @duration - @end_trim_length - @start_trim_length
130 | elsif ! @end_trim_length.nil?
131 | $end_trim_opt = @duration - @end_trim_length
132 | end
133 | if @start_trim_length != "AUTO"
134 | $start_trim_opt = ' -ss ' + @start_trim_length.to_s
135 | end
136 | end
137 | stack margin: 15 do
138 | background lightcyan
139 | para "Press 'Preview' to hear the file you recorded. To trim file, enter the amount (in seconds) to trim from the start and end of the file and press 'Trim'.\n\nIf 'Start Trim' is set to Auto, auto-trim will be applied to start of file. If no trim at start is desired set this to be empty. After trimming, a preview window will open for your new file. Trim can be run as many times as is neccessary.\n\nPress 'Finish' to quit"
140 | end
141 | flow do
142 | @start_trim_length = "AUTO"
143 | para 'Start Trim'
144 | start_trim_input = edit_line text = @start_trim_length do
145 | if start_trim_input.text.downcase == "auto"
146 | @start_trim_length = "AUTO"
147 | else
148 | @start_trim_length = start_trim_input.text.to_f
149 | end
150 | end
151 | end
152 | flow do
153 | para 'End Trim'
154 | end_trim_input = edit_line do
155 | @end_trim_length = end_trim_input.text.to_f
156 | end
157 | end
158 | flow do
159 | preview = button "Preview"
160 | preview.click do
161 | if trimcheck.nil?
162 | command = Mpvpath + ' --force-window --no-terminal --keep-open=yes --title="Preview" --geometry=620x620 -lavfi-complex "[aid1]asplit=3[ao][a][b],[a]showwaves=600x240:n=1[a1],[a1]drawbox=0:0:600:240:t=120[a2],[b]showwaves=600x240:mode=cline:colors=0x00FFFF:split_channels=1[b2],[a2][b2]overlay[vo]" ' + '"' + @finaloutput + '"'
163 | system(command)
164 | else
165 | command = Mpvpath + ' --force-window --no-terminal --keep-open=yes --title="Preview" --geometry=620x620 -lavfi-complex "[aid1]asplit=3[ao][a][b],[a]showwaves=600x240:n=1[a1],[a1]drawbox=0:0:600:240:t=120[a2],[b]showwaves=600x240:mode=cline:colors=0x00FFFF:split_channels=1[b2],[a2][b2]overlay[vo]" ' + '"'+ @pretrim + '"'
166 | system(command)
167 | end
168 | end
169 | trim = button "Trim"
170 | trim.click do
171 | #set up trim
172 | if trimcheck.nil?
173 | SetUpTrim(@finaloutput)
174 | File.rename(@finaloutput, @pretrim)
175 | trimcheck = 1
176 | else
177 | SetUpTrim(@pretrim)
178 | end
179 | if @start_trim_length == "AUTO"
180 | if ! @end_trim_length.nil? && @end_trim_length != 0.0
181 | precommand = Ffmpegpath + ' -i ' + '"' + @pretrim + '"' + ' -af silenceremove=start_threshold=-57dB:start_duration=1:start_periods=1 -f wav -c:a ' + $codec_choice + ' -ar ' + $sample_rate_choice + ' -y -rf64 auto ' + @trimtemp
182 | system(precommand)
183 | SetUpTrim(@trimtemp)
184 | postcommand = Ffmpegpath + " -i #{@trimtemp} -c copy -y -rf64 auto " + ' -t ' + $end_trim_opt.to_s + ' "' + @finaloutput + '"'
185 | system(postcommand)
186 | File.delete(@trimtemp)
187 | else
188 | command = Ffmpegpath + ' -i ' + '"' + @pretrim + '"' + ' -af silenceremove=start_threshold=-57dB:start_duration=1:start_periods=1 -f wav -c:a ' + $codec_choice + ' -ar ' + $sample_rate_choice + ' -y -rf64 auto ' + '"' + @finaloutput + '"'
189 | system(command)
190 | end
191 | else
192 | if ! @end_trim_length.nil? && @end_trim_length != 0.0
193 | command = Ffmpegpath + ' ' + $start_trim_opt + ' -i ' + '"' + @pretrim + '"' + ' -c copy -y -rf64 auto ' + ' -t ' + $end_trim_opt.to_s + ' "' + @finaloutput + '"'
194 | system(command)
195 | else
196 | command = Ffmpegpath + ' ' + $start_trim_opt + ' -i ' + '"' + @pretrim + '"' + ' -c copy -y -rf64 auto ' + ' "' + @finaloutput + '"'
197 | system(command)
198 | end
199 | end
200 | command = Mpvpath + ' --force-window --no-terminal --keep-open=yes --title="Preview" --geometry=620x620 -lavfi-complex "[aid1]asplit=3[ao][a][b],[a]showwaves=600x240:n=1[a1],[a1]drawbox=0:0:600:240:t=120[a2],[b]showwaves=600x240:mode=cline:colors=0x00FFFF:split_channels=1[b2],[a2][b2]overlay[vo]" ' + '"' + @finaloutput + '"'
201 | system(command)
202 | end
203 | close = button "Finish"
204 | close.click do
205 | File.delete($waveform_pic)
206 | close()
207 | end
208 | end
209 | end
210 | end
211 |
212 | flow margin: 2 do
213 | para "Select Channel(s)"
214 | if sox_channels == '1 2'
215 | sox_channels_saved = '1 and 2'
216 | elsif sox_channels == '3 4'
217 | sox_channels_saved = '3 and 4'
218 | else
219 | sox_channels_saved = sox_channels
220 | end
221 | channels = list_box items: ["1", "2", "1 and 2", "3 and 4"],
222 | width: 100, choose: sox_channels_saved do |list|
223 | if list.text == '1 and 2'
224 | sox_channels = '1 2'
225 | elsif list.text == '3 and 4'
226 | sox_channels = '3 4'
227 | else
228 | sox_channels = list.text
229 | end
230 | if sox_channels == "1 2"
231 | ffmpeg_channels = 'stereo'
232 | elsif sox_channels == "3 4"
233 | ffmpeg_channels = 'stereo'
234 | else
235 | ffmpeg_channels = 'mono'
236 | end
237 | end
238 | para "\n\n"
239 | para "Sample Rate"
240 | if $sample_rate_choice == '44100'
241 | sample_rate_saved = "44.1 kHz"
242 | elsif $sample_rate_choice == '48000'
243 | sample_rate_saved = "48 kHz"
244 | elsif $sample_rate_choice == '96000'
245 | sample_rate_saved = "96 kHz"
246 | end
247 | samplerate = list_box items: ["44.1 kHz", "48 kHz", "96 kHz"],
248 | width: 100, choose: sample_rate_saved do |list|
249 | if list.text == '44.1 kHz'
250 | $sample_rate_choice = '44100'
251 | elsif list.text == '48 kHz'
252 | $sample_rate_choice = '48000'
253 | elsif list.text == '96 kHz'
254 | $sample_rate_choice = '96000'
255 | end
256 | end
257 | para "\n\n"
258 | para "Bit Depth"
259 | if $codec_choice == 'pcm_s16le'
260 | codec_saved = "16 bit"
261 | elsif $codec_choice == 'pcm_s24le'
262 | codec_saved = "24 bit"
263 | end
264 | bitdepth = list_box items: ["16 bit", "24 bit"],
265 | width: 100, choose: codec_saved do |list|
266 | if list.text == '16 bit'
267 | $codec_choice = 'pcm_s16le'
268 | elsif list.text == '24 bit'
269 | $codec_choice = 'pcm_s24le'
270 | end
271 | end
272 | end
273 |
274 | stack margin: 10 do
275 | button "Choose Output Directory" do
276 | $outputdir = ask_open_folder
277 | @destination.replace "#{$outputdir}"
278 | end
279 | flow do
280 | destination_prompt = para "File will be saved to:"
281 | @destination = para "#{$outputdir}", underline: "single"
282 | end
283 | end
284 |
285 | stack margin: 10 do
286 | button "Choose File Name" do
287 | $filename = ask("Please Enter File Name")
288 | if $filename == ''
289 | @outputfile.replace "#{$filename}"
290 | else
291 | @outputfile.replace "#{$filename}.wav"
292 | end
293 | end
294 | flow do
295 | output_prompt = para "File will be saved as:"
296 | @outputfile = para "#{$filename}", underline: "single"
297 | end
298 | end
299 |
300 | flow do
301 | preview = button "Preview"
302 | preview.click do
303 | BufferCheck($sample_rate_choice)
304 | Soxcommand = Soxpath + ' -r ' + $sample_rate_choice + ' -b 32 -L -e signed-integer --buffer ' + $soxbuffer + ' -p remix ' + sox_channels
305 | FFmpegSTART = Ffmpegpath + ' -channel_layout ' + ffmpeg_channels + ' -i - '
306 | FFmpegPreview = '-f wav -c:a ' + 'pcm_s16le -dither_method triangular' + ' -ar ' + '44100' + ' -'
307 | FFplaycommand = Ffplaypath + ' -window_title "AudioRecorder" -f lavfi ' + '"' + 'amovie=\'pipe\:0\'' + ',' + FILTER_CHAIN + '"'
308 | ffmpegcommand = FFmpegSTART + FFmpegPreview
309 | command = Soxcommand + ' | ' + ffmpegcommand + ' | ' + FFplaycommand
310 | system(command)
311 | end
312 |
313 | record = button "Record"
314 | record.click do
315 | if ! defined? $record_iteration
316 | $record_iteration = 1
317 | else
318 | $record_iteration = $record_iteration + 1
319 | end
320 | if $outputdir.nil?
321 | $outputdir = ''
322 | end
323 | $waveform_pic = $outputdir + '/' + 'AUDIORECORDERTEMP' + $record_iteration.to_s + '.jpg'
324 | BufferCheck($sample_rate_choice)
325 | @tempfileoutput = '"' + $outputdir + '/' + $filename + '_temp.wav' + '"'
326 | @fileoutput = $outputdir + '/' + $filename + '.wav'
327 | if $filename == ''
328 | alert "Please enter an output file name!"
329 | elsif File.exist?(@fileoutput)
330 | alert "A File named #{$filename} already exists at that location!"
331 | elsif ! File.exist?($outputdir)
332 | alert "Please enter a valid output Directory!"
333 | else
334 | Soxcommand = Soxpath + ' -r ' + $sample_rate_choice + ' -b 32 -L -e signed-integer --buffer ' + $soxbuffer + ' -p remix ' + sox_channels
335 | FFmpegSTART = Ffmpegpath + ' -channel_layout ' + ffmpeg_channels + ' -i - '
336 | FFmpegRECORD = '-f wav -c:a ' + $codec_choice + ' -dither_method triangular -ar ' + $sample_rate_choice + ' -metadata comment="" -y -rf64 auto ' + @tempfileoutput
337 | FFmpegPreview = ' -f wav -c:a ' + 'pcm_s16le -dither_method triangular' + ' -ar ' + '44100' + ' -'
338 | FFplaycommand = Ffplaypath + ' -window_title "AudioRecorder" -f lavfi ' + '"' + 'amovie=\'pipe\:0\'' + ',' + FILTER_CHAIN + '"'
339 | ffmpegcommand = FFmpegSTART + FFmpegRECORD + FFmpegPreview
340 | syscommand1 = Soxcommand + ' | ' + ffmpegcommand + ' | ' + FFplaycommand
341 | syscommand2 = Ffmpegpath + ' -i ' + @tempfileoutput + ' -lavfi showwavespic=split_channels=1:s=500x150:colors=blue -y ' + $waveform_pic + ' -c copy ' + "'" + @fileoutput + "'" + ' && rm ' + @tempfileoutput
342 | system(syscommand1) && system(syscommand2)
343 | if $embedbext == 'true'
344 | EmbedBEXT(@fileoutput)
345 | end
346 | PostRecord(@fileoutput)
347 | end
348 | end
349 |
350 | button "Edit BWF Metadata" do
351 | window(title: "Edit BWF Metadata", width: 600, height: 500) do
352 | background aliceblue
353 | stack do
354 | para "Please Make Selections"
355 | para "Originator"
356 | originator_choice = edit_line text = $originator do
357 | $originator = originator_choice.text
358 | end
359 | para "Coding History"
360 | history_choice = edit_box text = $history do
361 | $history = history_choice.text
362 | end
363 | flow do
364 | bextswitch = check
365 | if $embedbext == 'true'
366 | bextswitch.checked = true
367 | elsif $embedbext =='false'
368 | bextswitch.checked = false
369 | end
370 | para "Embed BFW Metadata?"
371 | bextswitch.click do
372 | if bextswitch.checked?
373 | $embedbext = 'true'
374 | else
375 | $embedbext = 'false'
376 | end
377 | end
378 | end
379 | button "Save Settings" do
380 | config['destination'] = $outputdir
381 | config['samplerate'] = $sample_rate_choice
382 | config['channels'] = sox_channels
383 | config['codec'] = $codec_choice
384 | config['orig'] = $originator
385 | config['hist'] = $history
386 | config['bext'] = $embedbext
387 | File.open(configuration_file, 'w') {|f| f.write config.to_yaml }
388 | close()
389 | end
390 | close = button "Cancel"
391 | close.click do
392 | close()
393 | end
394 | end
395 | end
396 | end
397 |
398 | button "Save Settings" do
399 | config['destination'] = $outputdir
400 | config['samplerate'] = $sample_rate_choice
401 | config['channels'] = sox_channels
402 | config['codec'] = $codec_choice
403 | config['orig'] = $originator
404 | config['hist'] = $history
405 | config['bext'] = $embedbext
406 | File.open(configuration_file, 'w') {|f| f.write config.to_yaml }
407 | end
408 |
409 | exit = button "Quit"
410 | exit.click do
411 | exit()
412 | end
413 | end
414 | end
415 |
416 | #Cascadia Now!
417 |
--------------------------------------------------------------------------------
/current_interface.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/current_interface.gif
--------------------------------------------------------------------------------
/history.md:
--------------------------------------------------------------------------------
1 | # Development History
2 |
3 | **2018-08-30:** audiorecorder2 added to homebrew install formula. Can now be installed with option `--with-audiorecorder2`
4 |
5 | **2018-03-15:** In development version 2 (in linux) tested with twenty minute recording at 24 bit/96 kHz stereo recording. File analyzed for interstitial errors using Wavelab Elements 9.5 global analysis with none detected.
6 |
7 | **2017-12-26:** Version 0.1.08 released. Mainly typo fixes.
8 |
9 | **2017-12-14:** Version 0.1.07 released. Fix bug. Stricter man page syntax.
10 |
11 | **2017-10-18:** Version 0.1.06 released. Improved help message and man page.
12 |
13 | **2017-10-01:** Version 0.1.05 released. Deletes BWF Metaedit from the package and uses its homebrew formula instead.
14 |
15 | **2017-08-22:** Version 0.1.04 released. Mainly doc fixes.
16 |
17 | **2017-06-05:** Version 0.1.03 released. Linux install instructions, man page and Code of Conduct have been added.
18 |
19 | **2017-04-25:** Version 0.1.02 released. Includes font support for filters in Linux. (Tested in Ubuntu 16.04).
20 |
21 | **2017-04-11:** Version 0.1.01 released. Contains some basic interface workarounds to decrease reliance on Pashua for user input. This makes audiorecorder able to run in a linux environment (further reliability testing for non macOS systems is underway).
22 |
23 | **2017-03-11:** Major redesign of post-digitization functions and GUI. Audiorecorder now supports trimming of start and end of files via manual specification as well as auto-trim of silence at the start of files. Preview and post-digitization GUI now incorporate waveforms of the digitized audio to aid in trimming. All testing has been negative for dropped samples.
24 |
25 | **2017-03-04:** For the new release changes have been made to streamline the way audiorecorder handles input channels. This will prevent it from being overwhelmed by A/D converters that output many empty tracks along with the desired tracks (such as the Apogee Symphony). In two 55 minute tests and one 30 minute no drops or problems were detected via Wavelab analysis. Due to more efficient management of data the current buffering now has increased the latency for mono captures. A next step will be to see how much buffering can be safely lowered.
26 |
27 | **2017-02-24:** Changes appear to have been successful for adapting audiorecorder to macOS 10.12.03. In testing it was discovered that audiorecorder has issues with A/D converters that have a large number of output tracks (such as sixteen as opposed to two). Current audiorecorder head appears to be stable for two track A/D converters and testing is underway to expand its ability to deal with larger multi-track converters.
28 |
29 | **2017-02-23:** Due to some issues that were reported with macOS 10.12.03, some changes to buffering have been made and are currently being tested.
30 |
31 | **2017-02-15:** Ability to select which channel to record has been added to the GUI. This option was tested with a 25 minute ingest on 2013 Macbook Air with no dropped samples detected audibly or vie Wavelab global analysis. Some glitches with file trimming were resolved.
32 |
33 | **2017-01-20:** Initial post digitization functions have been included via a basic GUI. These include ability to preview file with and without silence trimming, and an option to create a silence trimmed version of file. The spectrograph has also been changed to scroll for easier viewability. Further testing has not detected any dropped samples either audibly or via Wavelab global analysis.
34 |
35 | **2016-12-22:** Current build was tested with a 40 minute transfer on the 2013 Macbook Air with no dropped samples detected either audibly or via Wavelab's global analysis tool. Testing continues...
36 |
--------------------------------------------------------------------------------
/macOS/audiorecorder2-osx.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/macOS/audiorecorder2-osx.tgz
--------------------------------------------------------------------------------
/numbered_interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amiaopensource/audiorecorder/50f19e52057852cb95068dcd8543942a6ff1cffc/numbered_interface.png
--------------------------------------------------------------------------------