mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
2
Commits
f93e6a7d7c
...
test_sound
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22771c7f3a | ||
|
|
6d60a2017c |
No files matched your search
+103
-8
@@ -31,14 +31,23 @@ except Exception as e:
|
|||||||
print(f"Module 'rasterio' is not available: {e}")
|
print(f"Module 'rasterio' is not available: {e}")
|
||||||
_rasterio_loaded = False
|
_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 functools import reduce
|
||||||
|
|
||||||
from numpy import sqrt
|
import numpy as np
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from tools import trace, timer, logger_exception
|
from tools import trace, timer, logger_exception
|
||||||
|
|
||||||
from View.Tools.PamhyrWindow import PamhyrWindow
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
|
from View.WaitingDialog import WaitingDialog
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
QKeySequence, QIcon, QPixmap,
|
QKeySequence, QIcon, QPixmap,
|
||||||
@@ -349,7 +358,8 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
"action_add": self._add_custom_plot,
|
"action_add": self._add_custom_plot,
|
||||||
"action_export": self._export,
|
"action_export": self._export,
|
||||||
# "action_export": self.export_current,
|
# "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:
|
if _rasterio_loaded:
|
||||||
actions["action_Geo_tiff"] = self.import_geotiff
|
actions["action_Geo_tiff"] = self.import_geotiff
|
||||||
@@ -357,6 +367,12 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
self.find(QAction, "action_Geo_tiff")\
|
self.find(QAction, "action_Geo_tiff")\
|
||||||
.setEnabled(False)
|
.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:
|
if len(self._results) > 1:
|
||||||
self.find(QAction, "action_reload").setEnabled(False)
|
self.find(QAction, "action_reload").setEnabled(False)
|
||||||
|
|
||||||
@@ -959,7 +975,7 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
map(
|
map(
|
||||||
lambda p:
|
lambda p:
|
||||||
p.get_ts_key(timestamp, "V") /
|
p.get_ts_key(timestamp, "V") /
|
||||||
sqrt(9.81 * (
|
np.sqrt(9.81 * (
|
||||||
p.geometry.wet_area(
|
p.geometry.wet_area(
|
||||||
p.get_ts_key(timestamp, "Z")) /
|
p.get_ts_key(timestamp, "Z")) /
|
||||||
p.geometry.wet_width(
|
p.geometry.wet_width(
|
||||||
@@ -973,7 +989,7 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
map(
|
map(
|
||||||
lambda p:
|
lambda p:
|
||||||
p.get_ts_key(timestamp, "V") /
|
p.get_ts_key(timestamp, "V") /
|
||||||
sqrt(9.81 * (
|
np.sqrt(9.81 * (
|
||||||
p.geometry.wet_area(
|
p.geometry.wet_area(
|
||||||
p.get_ts_key(timestamp, "Z")) /
|
p.get_ts_key(timestamp, "Z")) /
|
||||||
p.geometry.wet_width(
|
p.geometry.wet_width(
|
||||||
@@ -986,7 +1002,7 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
map(
|
map(
|
||||||
lambda p:
|
lambda p:
|
||||||
p.get_ts_key(timestamp, "V") /
|
p.get_ts_key(timestamp, "V") /
|
||||||
sqrt(9.81 * (
|
np.sqrt(9.81 * (
|
||||||
p.geometry.wet_area(
|
p.geometry.wet_area(
|
||||||
p.get_ts_key(timestamp, "Z")) /
|
p.get_ts_key(timestamp, "Z")) /
|
||||||
p.geometry.wet_width(
|
p.geometry.wet_width(
|
||||||
@@ -1122,7 +1138,7 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
if self._current_results != 2:
|
if self._current_results != 2:
|
||||||
fr = my_dict[dict_y["froude"]] = list(
|
fr = my_dict[dict_y["froude"]] = list(
|
||||||
map(lambda z, v:
|
map(lambda z, v:
|
||||||
v / sqrt(9.81 * (
|
v / np.sqrt(9.81 * (
|
||||||
profile.geometry.wet_area(z) /
|
profile.geometry.wet_area(z) /
|
||||||
profile.geometry.wet_width(z))
|
profile.geometry.wet_width(z))
|
||||||
), z, v)
|
), z, v)
|
||||||
@@ -1131,7 +1147,7 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
fr1 = list(
|
fr1 = list(
|
||||||
map(lambda z, v:
|
map(lambda z, v:
|
||||||
v /
|
v /
|
||||||
sqrt(9.81 * (
|
np.sqrt(9.81 * (
|
||||||
profile1.geometry.wet_area(z) /
|
profile1.geometry.wet_area(z) /
|
||||||
profile1.geometry.wet_width(z))
|
profile1.geometry.wet_width(z))
|
||||||
), z1, v1)
|
), z1, v1)
|
||||||
@@ -1139,7 +1155,7 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
fr2 = list(
|
fr2 = list(
|
||||||
map(lambda z, v:
|
map(lambda z, v:
|
||||||
v /
|
v /
|
||||||
sqrt(9.81 * (
|
np.sqrt(9.81 * (
|
||||||
profile2.geometry.wet_area(z) /
|
profile2.geometry.wet_area(z) /
|
||||||
profile2.geometry.wet_width(z))
|
profile2.geometry.wet_width(z))
|
||||||
), z2, v2)
|
), z2, v2)
|
||||||
@@ -1313,3 +1329,82 @@ class ResultsWindow(PamhyrWindow):
|
|||||||
|
|
||||||
for p in self._additional_plot:
|
for p in self._additional_plot:
|
||||||
self._additional_plot[p].add_imported_plot(data)
|
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()
|
||||||
@@ -239,6 +239,9 @@ class MainTranslate(UnitTranslate):
|
|||||||
"Results comparison with two "
|
"Results comparison with two "
|
||||||
"incompatible study version"
|
"incompatible study version"
|
||||||
)
|
)
|
||||||
|
self._dict["playing_sound"] = _translate(
|
||||||
|
"MainWindow", "Playing sound..."
|
||||||
|
)
|
||||||
|
|
||||||
self._dict["x"] = _translate("MainWindow", "X (m)")
|
self._dict["x"] = _translate("MainWindow", "X (m)")
|
||||||
self._dict["y"] = _translate("MainWindow", "Y (m)")
|
self._dict["y"] = _translate("MainWindow", "Y (m)")
|
||||||
|
|||||||
@@ -240,6 +240,7 @@
|
|||||||
<addaction name="action_reload"/>
|
<addaction name="action_reload"/>
|
||||||
<addaction name="action_Geo_tiff"/>
|
<addaction name="action_Geo_tiff"/>
|
||||||
<addaction name="action_import_data"/>
|
<addaction name="action_import_data"/>
|
||||||
|
<addaction name="action_play_sound"/>
|
||||||
</widget>
|
</widget>
|
||||||
<action name="action_add">
|
<action name="action_add">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
@@ -301,6 +302,18 @@
|
|||||||
<string>Import data from SCV file</string>
|
<string>Import data from SCV file</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</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>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 443 B |
+393
-195
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user