store mic audio with toggle (#35595)
* store/send mic audio with toggle * script to extract audio from logs * change description and add translation placeholders * microphone icon * apply toggle in loggerd * add legnth and counter * startFrameIdx counter * Revert "change description and add translation placeholders" This reverts commitpull/35621/head7baa1f6de9
. * send mic data first and then calc * restore changed description/icon after revert * adjust fft samples to keep old time window * remove extract_audio.py since audio is now stored in qcam isntead of rlog * qt microphone recording icon * Revert "remove extract_audio.py since audio is now stored in qcam isntead of rlog" This reverts commit7a3a75bd8d
. * move extract_audio script and output file by default * remove length field * recording indicator swaps sides based on lhd/rhd * use record icon from comma body * Update toggle description Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> * update raylib toggle desc cause I did earlier * microphone --> soundPressure, audioData --> rawAudioData * cleanup unused var * update README * sidebar mic indicator instead of annotated camera * improve logic readability * remove startFrameIdx and sequenceNum * use Q_PROPERTY/setProperty so that update() is actually called on value change * specify old id for SoundPressure * fix typo --------- Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
parent
082f4c0aee
commit
dcd56ae09a
15 changed files with 166 additions and 35 deletions
@ -0,0 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:9fc1f7f31d41f26ea7d6f52b3096f7a91844a3b897bc233a8489253c46f0403b |
||||
size 6324 |
@ -0,0 +1,77 @@ |
||||
#!/usr/bin/env python3 |
||||
import os |
||||
import sys |
||||
import wave |
||||
import argparse |
||||
import numpy as np |
||||
|
||||
from openpilot.tools.lib.logreader import LogReader, ReadMode |
||||
|
||||
|
||||
def extract_audio(route_or_segment_name, output_file=None, play=False): |
||||
lr = LogReader(route_or_segment_name, default_mode=ReadMode.AUTO_INTERACTIVE) |
||||
audio_messages = list(lr.filter("rawAudioData")) |
||||
if not audio_messages: |
||||
print("No rawAudioData messages found in logs") |
||||
return |
||||
sample_rate = audio_messages[0].sampleRate |
||||
|
||||
audio_chunks = [] |
||||
total_frames = 0 |
||||
for msg in audio_messages: |
||||
audio_array = np.frombuffer(msg.data, dtype=np.int16) |
||||
audio_chunks.append(audio_array) |
||||
total_frames += len(audio_array) |
||||
full_audio = np.concatenate(audio_chunks) |
||||
|
||||
print(f"Found {total_frames} frames from {len(audio_messages)} audio messages at {sample_rate} Hz") |
||||
|
||||
if output_file: |
||||
if write_wav_file(output_file, full_audio, sample_rate): |
||||
print(f"Audio written to {output_file}") |
||||
else: |
||||
print("Audio extraction canceled.") |
||||
if play: |
||||
play_audio(full_audio, sample_rate) |
||||
|
||||
|
||||
def write_wav_file(filename, audio_data, sample_rate): |
||||
if os.path.exists(filename): |
||||
if input(f"File '{filename}' exists. Overwrite? (y/N): ").lower() not in ['y', 'yes']: |
||||
return False |
||||
|
||||
with wave.open(filename, 'wb') as wav_file: |
||||
wav_file.setnchannels(1) # Mono |
||||
wav_file.setsampwidth(2) # 16-bit |
||||
wav_file.setframerate(sample_rate) |
||||
wav_file.writeframes(audio_data.tobytes()) |
||||
return True |
||||
|
||||
|
||||
def play_audio(audio_data, sample_rate): |
||||
try: |
||||
import sounddevice as sd |
||||
|
||||
print("Playing audio... Press Ctrl+C to stop") |
||||
sd.play(audio_data, sample_rate) |
||||
sd.wait() |
||||
except KeyboardInterrupt: |
||||
print("\nPlayback stopped") |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
parser = argparse.ArgumentParser(description="Extract audio data from openpilot logs") |
||||
parser.add_argument("-o", "--output", help="Output WAV file path") |
||||
parser.add_argument("--play", action="store_true", help="Play audio with sounddevice") |
||||
parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name") |
||||
|
||||
if len(sys.argv) == 1: |
||||
parser.print_help() |
||||
sys.exit() |
||||
args = parser.parse_args() |
||||
|
||||
output_file = args.output |
||||
if not args.output and not args.play: |
||||
output_file = "extracted_audio.wav" |
||||
|
||||
extract_audio(args.route_or_segment_name.strip(), output_file, args.play) |
Loading…
Reference in new issue