Add scripts and templates, clean up audio logger

This commit is contained in:
Pi 2022-08-20 16:40:10 +03:00
parent eff8dde098
commit 2dece7dc9d
15 changed files with 205 additions and 133 deletions

View File

@ -10,16 +10,7 @@ cpal= { version = "0.13.5", features = ["jack"] }
anyhow = "1.0.61"
clap = "3.2.17"
hound = "3.4.0"
[target.'cfg(target_os = "android")'.dev-dependencies]
ndk-glue = "0.7"
[target.'cfg(target_os = "windows")'.dependencies]
windows = { version = "0.37", features = ["Win32_Media_Audio", "Win32_Foundation", "Win32_System_Com", "Win32_Devices_Properties", "Win32_Media_KernelStreaming", "Win32_System_Com_StructuredStorage", "Win32_System_Ole", "Win32_System_Threading", "Win32_Security", "Win32_System_SystemServices", "Win32_System_WindowsProgramming", "Win32_Media_Multimedia", "Win32_UI_Shell_PropertiesSystem"]}
num-traits = { version = "0.2.6", optional = true }
parking_lot = "0.12"
once_cell = "1.12"
chrono = "0.4.22"
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"))'.dependencies]
alsa = "0.6"
@ -27,27 +18,3 @@ nix = "0.23"
libc = "0.2.65"
parking_lot = "0.12"
jack = { version = "0.9", optional = true }
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
core-foundation-sys = "0.8.2" # For linking to CoreFoundation.framework and handling device name `CFString`s.
mach = "0.3" # For access to mach_timebase type.
[target.'cfg(target_os = "macos")'.dependencies]
coreaudio-rs = { version = "0.10", default-features = false, features = ["audio_unit", "core_audio"] }
[target.'cfg(target_os = "ios")'.dependencies]
coreaudio-rs = { version = "0.10", default-features = false, features = ["audio_unit", "core_audio", "audio_toolbox"] }
[target.'cfg(target_os = "emscripten")'.dependencies]
stdweb = { version = "0.1.3", default-features = false }
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
wasm-bindgen = { version = "0.2.58", optional = true }
js-sys = { version = "0.3.35" }
web-sys = { version = "0.3.35", features = [ "AudioContext", "AudioContextOptions", "AudioBuffer", "AudioBufferSourceNode", "AudioNode", "AudioDestinationNode", "Window", "AudioContextState"] }
[target.'cfg(target_os = "android")'.dependencies]
oboe = { version = "0.4", features = [ "java-interface" ] }
ndk = "0.7"
ndk-context = "0.1"
jni = "0.19"

View File

@ -2,71 +2,25 @@
//!
//! The input data is recorded to "$CARGO_MANIFEST_DIR/recorded.wav".
use clap::arg;
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use std::fs::File;
use std::io::BufWriter;
use std::path::Path;
use std::sync::{Arc, Mutex};
#[derive(Debug)]
struct Opt {
#[cfg(all(
any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"),
))]
jack: bool,
device: String,
}
impl Opt {
fn from_args() -> Self {
let app = clap::Command::new("record_wav").arg(arg!([DEVICE] "The audio device to use"));
#[cfg(all(
any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"),
))]
let app = app.arg(arg!(-j --jack "Use the JACK host"));
let matches = app.get_matches();
let device = matches.value_of("DEVICE").unwrap_or("default").to_string();
#[cfg(all(
any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"),
))]
return Opt {
jack: matches.is_present("jack"),
device,
};
#[cfg(any(
not(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd")),
))]
Opt { device }
}
}
use chrono::prelude::*;
fn main() -> Result<(), anyhow::Error> {
let opt = Opt::from_args();
// Manually check for flags. Can be passed through cargo with -- e.g.
// cargo run --release --example beep --features jack -- --jack
let host = if opt.jack {
cpal::host_from_id(cpal::available_hosts()
.into_iter()
.find(|id| *id == cpal::HostId::Jack)
.expect(
"make sure --features jack is specified. only works on OSes where jack is available",
)).expect("jack host unavailable")
} else {
cpal::default_host()
};
// Use jack host, requires the jack server to be running
let host = cpal::host_from_id(cpal::available_hosts()
.into_iter()
.find(|id| *id == cpal::HostId::Jack)
.expect(
"make sure feature jack is specified for cpal. only works on OSes where jack is available",
)).expect("jack host unavailable");
// Set up the input device and stream with the default input config.
let device = if opt.device == "default" {
host.default_input_device()
} else {
host.input_devices()?
.find(|x| x.name().map(|y| y == opt.device).unwrap_or(false))
}
.expect("failed to find input device");
let device = host.default_input_device()
.expect("failed to find input device");
println!("Input device: {}", device.name()?);
@ -75,47 +29,55 @@ fn main() -> Result<(), anyhow::Error> {
.expect("Failed to get default input config");
println!("Default input config: {:?}", config);
// The WAV file we're recording to.
const PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/recorded.wav");
// Location where files will be outputted
let path = Path::new("/home/shared/logger-raspi-setup/data/audio/");
let spec = wav_spec_from_config(&config);
let writer = hound::WavWriter::create(PATH, spec)?;
let writer = Arc::new(Mutex::new(Some(writer)));
// A flag to indicate that recording is in progress.
println!("Begin recording...");
for _ in 0..5 {
// The WAV file we're recording to.
let ts: String = Utc::now().format("%Y-%m-%dT%H-%M-%S.%f").to_string();
let file: String = path.to_str().unwrap().to_owned() + &ts + "_audio_data.wav";
// Run the input stream on a separate thread.
let writer_2 = writer.clone();
let err_fn = move |err| {
eprintln!("an error occurred on stream: {}", err);
};
let stream = match config.sample_format() {
cpal::SampleFormat::F32 => device.build_input_stream(
&config.into(),
move |data, _: &_| write_input_data::<f32, f32>(data, &writer_2),
err_fn,
)?,
cpal::SampleFormat::I16 => device.build_input_stream(
&config.into(),
move |data, _: &_| write_input_data::<i16, i16>(data, &writer_2),
err_fn,
)?,
cpal::SampleFormat::U16 => device.build_input_stream(
&config.into(),
move |data, _: &_| write_input_data::<u16, i16>(data, &writer_2),
err_fn,
)?,
};
stream.play()?;
// Let recording go for roughly three seconds.
std::thread::sleep(std::time::Duration::from_secs(3));
drop(stream);
writer.lock().unwrap().take().unwrap().finalize()?;
println!("Recording {} complete!", PATH);
let writer = hound::WavWriter::create(file.clone(), spec)?;
let writer = Arc::new(Mutex::new(Some(writer)));
// Run the input stream on a separate thread.
let writer_2 = writer.clone();
let config_2 = config.clone();
let err_fn = move |err| {
eprintln!("an error occurred on stream: {}", err);
};
let stream = match config.sample_format() {
cpal::SampleFormat::F32 => device.build_input_stream(
&config_2.into(),
move |data, _: &_| write_input_data::<f32, f32>(data, &writer_2),
err_fn,
)?,
cpal::SampleFormat::I16 => device.build_input_stream(
&config_2.into(),
move |data, _: &_| write_input_data::<i16, i16>(data, &writer_2),
err_fn,
)?,
cpal::SampleFormat::U16 => device.build_input_stream(
&config_2.into(),
move |data, _: &_| write_input_data::<u16, i16>(data, &writer_2),
err_fn,
)?,
};
// Start recording
println!("Begin recording at {}", Utc::now());
stream.play()?;
// Let recording go for roughly five seconds.
std::thread::sleep(std::time::Duration::from_secs(5));
drop(stream);
writer.lock().unwrap().take().unwrap().finalize()?;
println!("Recording {} complete!", file);
}
Ok(())
}

View File

@ -1 +0,0 @@
{"rustc_fingerprint":1011063074445675614,"outputs":{"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.62.1 (e092d0b6b 2022-07-16)\nbinary: rustc\ncommit-hash: e092d0b6b43f2de967af0887873151bb1c0b18d3\ncommit-date: 2022-07-16\nhost: x86_64-unknown-linux-gnu\nrelease: 1.62.1\nLLVM version: 14.0.5\n","stderr":""},"15697416045686424142":{"success":false,"status":"exit status: 1","code":1,"stdout":"","stderr":"error: `-Csplit-debuginfo` is unstable on this platform\n\n"},"10376369925670944939":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/julius/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}

View File

@ -0,0 +1,52 @@
#!/usr/bin/python3
import board
import time
import busio
import adafruit_ads1x15.ads1015 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
from time import sleep, strftime
# Create the I2C bus
i2c = busio.I2C(board.SCL, board.SDA)
# Create the ADC object using the I2C bus
ads = ADS.ADS1015(i2c)
# Create single-ended input on channel 0
tmp36 = AnalogIn(ads, ADS.P0)
# Attempting to create a single-ended input on channel 1
depthS = AnalogIn(ads, ADS.P1)
# Subtract the offset from the sensor voltage
# and convert chan.voltage * (1 degree C / 0.01V) = Degrees Celcius
temperatureC = (tmp36.voltage - 0.5) / 0.01
# Open the file to write down the results
timestr = time.strftime("%Y-%m-%dT%H-%M-%S")
filename = "/home/shared/logger-raspi-setup/data/depth-temp/" + timestr + "depth_temperature_data.csv"
#depthM = ((depthS.voltage * 31.848) - 22.93)
#Attempting to round the figure to a more intelligible figure
#rounddepth = round(depthM, ndigits)
#psi = depthS.voltage * 104.1666667 - 75
#bar = psi * 14.503773800722
with open(filename, "w") as f:
f.write("time and date, temperature (C), Voltage of depth sensor (V), Depth (m)\n")
while True:
depthM = ((depthS.voltage * 31.848) - 22.93)
rounddepth = round(depthM, 2)
roundtemp = round(temperatureC, 2)
roundvolts = round(depthS.voltage, 3)
print((str(roundtemp) + " °C ") + (str(roundvolts) + " V ") + (str(rounddepth) + " m"))
f.write(time.strftime("%Y-%m-%d %H:%M:%S") + ",")
f.write((str(roundtemp) + " °C ") + "," + (str(roundvolts) + " V ") + "," + (str(rounddepth) + " m\n"))
time.sleep(3)

29
gps-logger/record-gps.py Normal file
View File

@ -0,0 +1,29 @@
#!/usr/bin/python3
from gps import *
from time import sleep, strftime
filename = "/home/shared/logger-raspi-setup/data/gps/" + time.strftime("%Y-%m-%dT%H-%M-%S") + "_GPS_data.csv"
# filename = "/mnt/myssd/GPS_Data" + timestr +".csv"
with open(filename, "w", 1) as f:
gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE)
f.write("GPStime utc,latitude,longitude,speed,sats in view\n")
try:
while True:
report = gpsd.next()
if report["class"] == "TPV":
GPStime = str(getattr(report,"time",""))
lat = str(getattr(report,"lat",0.0))
lon = str(getattr(report,"lon",0.0))
speed = str(getattr(report,"speed","nan"))
sats = str(len(gpsd.satellites))
f.write(GPStime + "," + lat +"," + lon + "," + speed + "," + sats + "\n")
time.sleep(5)
except (KeyboardInterrupt, SystemExit): # when you press ctrl+c
print("Done.\nExiting.")
f.close()

View File

@ -2,4 +2,8 @@
# Raspberry Pi water pressure sensor
https://www.circuito.io/app?components=9443,200000,267055
https://www.circuito.io/app?components=9443,200000,267055
# Setting up Jack on Raspberry Pi
https://wiki.linuxaudio.org/wiki/raspberrypi

View File

12
scripts/list-usb-devices.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do
(
syspath="${sysdevpath%/dev}"
devname="$(udevadm info -q name -p $syspath)"
[[ "$devname" == "bus/"* ]] && exit
eval "$(udevadm info -q property --export -p $syspath)"
[[ -z "$ID_SERIAL" ]] && exit
echo "/dev/$devname - $ID_SERIAL"
)
done

5
scripts/setup-audio.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
# Install jackd
# Audio setup utils

16
scripts/setup-gps.sh Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
sudo apt-get update && sudo apt-get install -y \
gpsd gpsd-clients
sudo systemctl stop gpsd.socket
sudo systemctl disable gpsd.socket
device="/dev/ttyUSB0"
sudo gpsd ${device} -F /var/run/gpsd.sock
sudo sed -i "s|DEVICES=\"\"|DEVICES=\"${device}\"|g" /etc/default/gpsd
echo "START_DAEMON=\"true\"" | sudo tee -a /etc/default/gpsd

3
scripts/start-all.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
(trap 'kill 0' SIGINT; ./scripts/start-gps.sh & ./scripts/start-audio.sh)

9
scripts/start-audio.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
# Start jack server
sh scripts/start-jack.sh
# Start recording
cd audio-logger && cargo run

3
scripts/start-gps.sh Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/sh
python /home/shared/logger-raspi-setup/gps-logger/record-gps.py

7
scripts/start-jack.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
# Get soundcard name
soundcard=$(grep USB /proc/asound/cards | grep -oe "\[.*]" | tr -d "[] ")
# Start jack server
/usr/bin/jackd -P75 -d alsa -d hw:${soundcard} -r 44100 -p 512 -n 3 &

View File

@ -34,9 +34,9 @@
## Set up logging
## Set up recording
### 1. Sound recording
### 1. Audio
@ -47,3 +47,7 @@
### 3. Water pressure
## Test & run