Compare commits

...
2 Commits
Author SHA1 Message Date
Theophile Terraz 22771c7f3a debug + pep8 2025-11-06 16:40:12 +01:00
Theophile Terraz 6d60a2017c add sound option in results for Q 2025-11-06 16:28:59 +01:00
5 changed files with 512 additions and 203 deletions

No files matched your search

+103 -8
View File
@@ -31,14 +31,23 @@ except Exception as e:
print(f"Module 'rasterio' is not available: {e}")
_rasterio_loaded = False
try:
import pyaudio
import wave
_audio_loaded = True
except Exception as e:
print(f"Either 'pyaudio' or 'wave' is not available: {e}")
_audio_loaded = False
from functools import reduce
from numpy import sqrt
import numpy as np
from datetime import datetime
from tools import trace, timer, logger_exception
from View.Tools.PamhyrWindow import PamhyrWindow
from View.WaitingDialog import WaitingDialog
from PyQt5.QtGui import (
QKeySequence, QIcon, QPixmap,
@@ -349,7 +358,8 @@ class ResultsWindow(PamhyrWindow):
"action_add": self._add_custom_plot,
"action_export": self._export,
# "action_export": self.export_current,
"action_import_data": self.import_data
"action_import_data": self.import_data,
"action_play_sound": self.play_sound
}
if _rasterio_loaded:
actions["action_Geo_tiff"] = self.import_geotiff
@@ -357,6 +367,12 @@ class ResultsWindow(PamhyrWindow):
self.find(QAction, "action_Geo_tiff")\
.setEnabled(False)
if _audio_loaded:
actions["action_play_sound"] = self.play_sound
else:
self.find(QAction, "action_play_sound")\
.setVisible(False)
if len(self._results) > 1:
self.find(QAction, "action_reload").setEnabled(False)
@@ -959,7 +975,7 @@ class ResultsWindow(PamhyrWindow):
map(
lambda p:
p.get_ts_key(timestamp, "V") /
sqrt(9.81 * (
np.sqrt(9.81 * (
p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width(
@@ -973,7 +989,7 @@ class ResultsWindow(PamhyrWindow):
map(
lambda p:
p.get_ts_key(timestamp, "V") /
sqrt(9.81 * (
np.sqrt(9.81 * (
p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width(
@@ -986,7 +1002,7 @@ class ResultsWindow(PamhyrWindow):
map(
lambda p:
p.get_ts_key(timestamp, "V") /
sqrt(9.81 * (
np.sqrt(9.81 * (
p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width(
@@ -1122,7 +1138,7 @@ class ResultsWindow(PamhyrWindow):
if self._current_results != 2:
fr = my_dict[dict_y["froude"]] = list(
map(lambda z, v:
v / sqrt(9.81 * (
v / np.sqrt(9.81 * (
profile.geometry.wet_area(z) /
profile.geometry.wet_width(z))
), z, v)
@@ -1131,7 +1147,7 @@ class ResultsWindow(PamhyrWindow):
fr1 = list(
map(lambda z, v:
v /
sqrt(9.81 * (
np.sqrt(9.81 * (
profile1.geometry.wet_area(z) /
profile1.geometry.wet_width(z))
), z1, v1)
@@ -1139,7 +1155,7 @@ class ResultsWindow(PamhyrWindow):
fr2 = list(
map(lambda z, v:
v /
sqrt(9.81 * (
np.sqrt(9.81 * (
profile2.geometry.wet_area(z) /
profile2.geometry.wet_width(z))
), z2, v2)
@@ -1313,3 +1329,82 @@ class ResultsWindow(PamhyrWindow):
for p in self._additional_plot:
self._additional_plot[p].add_imported_plot(data)
def play_sound(self):
def get_sine_wave(frequency, duration,
sample_rate=44100, amplitude=4096):
t = np.linspace(0, duration, int(sample_rate*duration))
return amplitude*np.sin(2*np.pi*frequency*t)
if not _audio_loaded:
return
# results
results = self._results[self._current_results[0]]
if results is None:
return
# reach
reach = results.river.reachs[self._get_current_reach()]
profile_id = self._get_current_profile()
profile = reach.profile(profile_id)
t = self._timestamps
q = profile.get_key("Q")
scale = []
low = 30
high = 84
for k in range(low, high):
note = 440*2**((k-49)/12)
scale.append(note) # add musical note
n_notes = len(scale) # number of musical notes
# rescale
# we start at low to high
tmax = max(t)
tmin = min(t)
qmax = max(q)
qmin = min(q)
qfact = (n_notes) / (qmax - qmin + 1)
for i in range(len(q)):
q[i] = int((q[i] - qmin) * qfact)
nq = [q[0]] # (notes)
dq = [0.1] # durée
for i in range(len(t)-1):
if q[i] == q[i+1]:
dq[-1] += 0.1
else:
nq.append(q[i+1])
dq.append(0.1)
wq = []
volume = 2048
for i in range(len(dq)):
new_w = get_sine_wave(frequency=scale[nq[i]],
duration=dq[i],
amplitude=volume)
wq = np.concatenate((wq, new_w))
p = pyaudio.PyAudio()
chunk = 1048
stream = p.open(format=p.get_format_from_width(2),
channels=1,
rate=44100,
output=True)
def fn():
i = 0
while i < len(wq):
stream.write(
wq[i:min(i+chunk, len(wq))].astype(np.int16).tobytes()
)
i += chunk
dlg = WaitingDialog(
payload_fn=fn,
title="playing_sound",
parent=self
)
dlg.exec_()
stream.stop_stream()
stream.close()
p.terminate()
+3
View File
@@ -239,6 +239,9 @@ class MainTranslate(UnitTranslate):
"Results comparison with two "
"incompatible study version"
)
self._dict["playing_sound"] = _translate(
"MainWindow", "Playing sound..."
)
self._dict["x"] = _translate("MainWindow", "X (m)")
self._dict["y"] = _translate("MainWindow", "Y (m)")
+13
View File
@@ -240,6 +240,7 @@
<addaction name="action_reload"/>
<addaction name="action_Geo_tiff"/>
<addaction name="action_import_data"/>
<addaction name="action_play_sound"/>
</widget>
<action name="action_add">
<property name="icon">
@@ -301,6 +302,18 @@
<string>Import data from SCV file</string>
</property>
</action>
<action name="action_play_sound">
<property name="icon">
<iconset>
<normaloff>ressources/multimedia-volume-control-symbolic.symbolic.png</normaloff>ressources/multimedia-volume-control-symbolic.symbolic.png</iconset>
</property>
<property name="text">
<string>play_sound</string>
</property>
<property name="toolTip">
<string>Play discharge as sound</string>
</property>
</action>
</widget>
<resources/>
<connections/>
Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

+393 -195
View File
File diff suppressed because it is too large. Load diff