-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed sound bug, added new sound config and script for release
- Loading branch information
1 parent
07861cd
commit 7a5a807
Showing
10 changed files
with
431 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -129,3 +129,5 @@ venv.bak/ | |
.mypy_cache/ | ||
.dmypy.json | ||
dmypy.json | ||
|
||
config_files.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,301 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import alsaaudio\n", | ||
"import time\n", | ||
"from multiprocessing import Process\n", | ||
"from threading import Thread\n", | ||
"from pathlib import Path\n", | ||
"from threading import Thread, Lock\n", | ||
"import wave" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 2, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"data": { | ||
"text/plain": [ | ||
"['null',\n", | ||
" 'jack',\n", | ||
" 'pulse',\n", | ||
" 'custom',\n", | ||
" 'default',\n", | ||
" 'sysdefault:CARD=excelsiorcard',\n", | ||
" 'dmix:CARD=excelsiorcard,DEV=0',\n", | ||
" 'dmix:CARD=excelsiorcard,DEV=3',\n", | ||
" 'dsnoop:CARD=excelsiorcard,DEV=0',\n", | ||
" 'dsnoop:CARD=excelsiorcard,DEV=3',\n", | ||
" 'hw:CARD=excelsiorcard,DEV=0',\n", | ||
" 'hw:CARD=excelsiorcard,DEV=3',\n", | ||
" 'plughw:CARD=excelsiorcard,DEV=0',\n", | ||
" 'plughw:CARD=excelsiorcard,DEV=3',\n", | ||
" 'usbstream:CARD=excelsiorcard']" | ||
] | ||
}, | ||
"execution_count": 2, | ||
"metadata": {}, | ||
"output_type": "execute_result" | ||
} | ||
], | ||
"source": [ | ||
"alsaaudio.pcms()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 3, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"class Dummy:\n", | ||
" def __getattr__(self, attr):\n", | ||
" return lambda *args, **kwargs: None" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 4, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"class SleepSpindleRealTimeStimulator():\n", | ||
" def __init__(self, soundname=None, lsl_streamer=Dummy(), stimulation_delay=0.0, inter_stim_delay=0.0):\n", | ||
" \"\"\"\n", | ||
" params: \n", | ||
" stimulation_delay (float): simple delay between a detection and a stimulation\n", | ||
" inter_stim_delay (float): time to wait between a stimulation and the next detection \n", | ||
" \"\"\"\n", | ||
" if soundname is None:\n", | ||
" self.soundname = 'stimulus.wav' # CHANGE HERE TO THE SOUND THAT YOU WANT. ONLY ADD THE FILE NAME, NOT THE ENTIRE PATH\n", | ||
" else:\n", | ||
" self.soundname = soundname\n", | ||
"# self._sound = Path(\".\").parent.parent / 'sounds' / self.soundname\n", | ||
" self._sound = f\"../sounds/{self.soundname}\"\n", | ||
" self._thread = None\n", | ||
" self._lock = Lock()\n", | ||
" self.last_detected_ts = time.time()\n", | ||
" self.wait_t = 0.4 # 400 ms\n", | ||
" self.delayer = None\n", | ||
" self.lsl_streamer = lsl_streamer\n", | ||
"\n", | ||
" # Initialize Alsa stuff\n", | ||
" # Open WAV file and set PCM device\n", | ||
" with wave.open(str(self._sound), 'rb') as f: \n", | ||
" device = 'custom'\n", | ||
" \n", | ||
" self.duration = f.getnframes() / float(f.getframerate())\n", | ||
" \n", | ||
" format = None\n", | ||
"\n", | ||
" # 8bit is unsigned in wav files\n", | ||
" if f.getsampwidth() == 1:\n", | ||
" format = alsaaudio.PCM_FORMAT_U8\n", | ||
" # Otherwise we assume signed data, little endian\n", | ||
" elif f.getsampwidth() == 2:\n", | ||
" format = alsaaudio.PCM_FORMAT_S16_LE\n", | ||
" elif f.getsampwidth() == 3:\n", | ||
" format = alsaaudio.PCM_FORMAT_S24_3LE\n", | ||
" elif f.getsampwidth() == 4:\n", | ||
" format = alsaaudio.PCM_FORMAT_S32_LE\n", | ||
" else:\n", | ||
" raise ValueError('Unsupported format')\n", | ||
"\n", | ||
" self.periodsize = f.getframerate() // 8\n", | ||
"\n", | ||
" try:\n", | ||
" self.pcm = alsaaudio.PCM(channels=f.getnchannels(), rate=f.getframerate(), format=format, periodsize=self.periodsize, device=device)\n", | ||
" except alsaaudio.ALSAAudioError as e:\n", | ||
"# print(\"WARNING: Could not open ALSA device as it is already playing a sound. To test stimulation, stop recording and try again.\")\n", | ||
" self.pcm = Dummy()\n", | ||
"\n", | ||
" raise e\n", | ||
" \n", | ||
" # Store data in list to avoid reopening the file\n", | ||
" self.wav_list = []\n", | ||
" while True:\n", | ||
" data = f.readframes(self.periodsize) \n", | ||
" if data:\n", | ||
" self.wav_list.append(data)\n", | ||
" else: \n", | ||
" break\n", | ||
" \n", | ||
" print(f\"DEBUG: Stimulator will play sound {self.soundname}, duration: {self.duration:.3f} seconds\")\n", | ||
"\n", | ||
"\n", | ||
" def play_sound(self):\n", | ||
" '''\n", | ||
" Open the wav file and play a sound\n", | ||
" '''\n", | ||
" print(len(self.wav_list[0]))\n", | ||
" for data in self.wav_list:\n", | ||
" self.pcm.write(data) \n", | ||
" \n", | ||
" # Added this to make sure the thread does not stop before the sound is done playing\n", | ||
" time.sleep(self.duration)\n", | ||
" \n", | ||
" def stimulate(self, detection_signal):\n", | ||
" for sig in detection_signal:\n", | ||
" # We detect a stimulation\n", | ||
" if sig:\n", | ||
" # Record time of stimulation\n", | ||
" ts = time.time()\n", | ||
" \n", | ||
" # Check if time since last stimulation is long enough\n", | ||
" if ts - self.last_detected_ts > self.wait_t:\n", | ||
" if not isinstance(self.delayer, Dummy):\n", | ||
" # If we have a delayer, notify it\n", | ||
" self.delayer.detected()\n", | ||
" # Send the LSL marer for the fast stimulation \n", | ||
" self.send_stimulation(\"FAST_STIM\", False)\n", | ||
" else:\n", | ||
" self.send_stimulation(\"STIM\", True)\n", | ||
"\n", | ||
" self.last_detected_ts = ts\n", | ||
"\n", | ||
" def send_stimulation(self, lsl_text, sound):\n", | ||
" # Send lsl stimulation\n", | ||
" self.lsl_streamer.push_marker(lsl_text)\n", | ||
" # Send sound to patient\n", | ||
" if sound:\n", | ||
" with self._lock:\n", | ||
" if self._thread is None: \n", | ||
" self._thread = Thread(target=self._t_sound, daemon=True)\n", | ||
" self._thread.start()\n", | ||
"\n", | ||
" \n", | ||
" def _t_sound(self):\n", | ||
" self.play_sound()\n", | ||
" with self._lock:\n", | ||
" self._thread = None\n", | ||
" \n", | ||
" def test_stimulus(self):\n", | ||
" with self._lock:\n", | ||
" if self._thread is None:\n", | ||
" self._thread = Thread(target=self._t_sound, daemon=True)\n", | ||
" self._thread.start()\n", | ||
"\n", | ||
" def add_delayer(self, delayer):\n", | ||
" self.delayer = delayer\n", | ||
" self.delayer.stimulate = lambda: self.send_stimulation(\"DELAY_STIM\", True)\n", | ||
"\n", | ||
" def __del__(self):\n", | ||
" print(\"DEBUG: releasing PCM\")\n", | ||
" del self.pcm" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 5, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"sound = 'stimulus.wav'" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 6, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"def sound_process():\n", | ||
"\n", | ||
" stimulator = SleepSpindleRealTimeStimulator(soundname=sound)\n", | ||
" stimulator.play_sound()\n", | ||
" time.sleep(1)\n", | ||
" stimulator.play_sound()\n", | ||
" del stimulator\n", | ||
" print(\"Done\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 7, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"DEBUG: Stimulator will play sound stimulus.wav, duration: 1.588 seconds\n", | ||
"22048\n", | ||
"22048\n", | ||
"DEBUG: releasing PCM\n", | ||
"Done\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"sound_process()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 8, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"DEBUG: Stimulator will play sound stimulus.wav, duration: 1.588 seconds\n", | ||
"22048\n", | ||
"22048\n", | ||
"DEBUG: releasing PCM\n", | ||
"Done\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"sound_proc = Process(target=sound_process)\n", | ||
"sound_proc.start()\n", | ||
"sound_proc.join()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 9, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"sound_proc.join()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.7.3" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
pcm.!default { | ||
type plug | ||
slave.pcm "softvol" | ||
} | ||
|
||
pcm.dmixer { | ||
type dmix | ||
ipc_key 1024 | ||
slave { | ||
pcm "hw:0,0" # Replace with your sound card device | ||
period_time 0 | ||
period_size 1024 | ||
buffer_size 8192 | ||
rate 48000 | ||
} | ||
bindings { | ||
0 0 | ||
1 1 | ||
} | ||
} | ||
|
||
ctl.dmixer { | ||
type hw | ||
card 0 # Replace with your sound card device | ||
} | ||
|
||
pcm.softvol { | ||
type softvol | ||
slave { | ||
pcm "dmixer" | ||
} | ||
control { | ||
name "SoftMaster" | ||
card 0 # Replace with your sound card device | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#!/bin/bash | ||
|
||
output_file="config_files.txt" | ||
|
||
# List of files to concatenate | ||
file_list=("/etc/asound.conf" "/etc/systemd/system/create_ap.service" "/etc/systemd/system/jupyter.service" "/etc/systemd/system/setup_tables.service" "/usr/local/bin/create_ap0.sh" "/etc/hostapd/hostapd.conf" "/etc/dnsmasq.conf" "/usr/local/bin/setup_tables.sh") | ||
|
||
# Create an empty output file | ||
echo -n > "$output_file" | ||
|
||
# Loop through each file | ||
for file_name in "${file_list[@]}"; do | ||
echo "File: $(basename "$file_name")" >> "$output_file" # Add file name | ||
echo "---------------------------------------------------" >> "$output_file" | ||
cat "$file_name" >> "$output_file" # Concatenate file content | ||
echo >> "$output_file" | ||
done | ||
|
||
echo "Concatenation completed. Output file: $output_file" |
Git LFS file not shown
Git LFS file not shown
Oops, something went wrong.