Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

translate the documentation of the sound module #25

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions resources/languages/french.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,11 @@
"agricultural_machines": {
"text": "Un ingénieur militaire vient de trouver un moyen particulièrement efficace pour transformer des machines agricoles obsolètes en engins d'assaut dévastateurs. La Milice saura en tirer profit lors de ses prochaines expéditions."
},
"researches_amonites": {
"text": "Les paléontologues sont parvenus à un accord avantageux avec l'évèque. Ce dernier ne s'opposera plus à leurs recherches sur les amonites, en échange de passe-droits plus que douteux. Il vaudrait mieux que les fidèles n'en apprennent rien, mais en attendant, réjouissons-nous des bénéfices à venir de ces recherches."
"researches_ammonites": {
"text": "Les paléontologues sont parvenus à un accord avantageux avec l’évêque. Ce dernier ne s'opposera plus à leurs recherches sur les ammonites, en échange de passe-droits plus que douteux. Il vaudrait mieux que les fidèles n'en apprennent rien, mais en attendant, réjouissons-nous des bénéfices à venir de ces recherches."
},
"storm_fear": {
"text": "Les craintes suscitées par les orages particulièrement violents de ces dernières semaines ont été habilement exploitées par l'Ordre. Les survivants sont désormais convaincus que l'évèque va intercéder en leur faveur pour apaiser la colère du Dragon des derniers jours."
"text": "Les craintes suscitées par les orages particulièrement violents de ces dernières semaines ont été habilement exploitées par l'Ordre. Les survivants sont désormais convaincus que l’évêque va intercéder en leur faveur pour apaiser la colère du Dragon des derniers jours."
},
"lottery": {
"text": "Une loterie est organisée par les citoyens pour se changer les idées. Ils trouvent ce jeu particulièrement satisfaisant, ce qui leur remonte le moral."
Expand All @@ -303,16 +303,16 @@
"text": "Eurêka ! Des documents décryptés par nos paléontologues contenaient des patrons d'instruments de menuiserie. Nous allons les mettre à profit pour améliorer l'efficacité de nos constructions."
},
"fire_church": {
"text": "Une église est en feu ! Non seulement l'origine de cet incendie est vraisemblablement criminelle, mais les survivants risquent de douter de l'efficacité de la protection de monseigneur l'évèque sur le campement."
"text": "Une église est en feu ! Non seulement l'origine de cet incendie est vraisemblablement criminelle, mais les survivants risquent de douter de l'efficacité de la protection de monseigneur l’évêque sur le campement."
},
"oleg": {
"Oleg": {
"text": "Un homme qui prétend se nommer Oleg et qui viendrait de ce qui était autrefois la Russie est arrive au camp. Nous n'avons pas l'habitude d'accepter des étrangers, mais les stocks d'armes conséquents qu'apporte Oleg faciliteront certainement son intégration en ces temps difficiles."
},
"dino_cave": {
"text": "Les paléontologues ont découvert une caverne où des dinosaures stockaient toutes leurs ressources ! Ils s'empressent de ramener toutes les vivres au campement."
},
"dino_attack": {
"text": "Une horde de compsognathus attaque votre campement sans prévenir. Les survivants sont affolés mais la milice parvient à contenir la crise moyennant quelques armes. De nombreux cadavres de ces petites bestioles sont parsemés dans votre camp, pour le plus grand bonheur des paléontologues qui s'empressent d'en subtiliser quelques-uns pour les étudier. Les autres sont utilisés pour regarnir vos réserves de nourriture."
"text": "Une horde de compsognathus attaque votre campement sans prévenir. La milice parvient à contenir la crise au prix de quelques armes. De nombreux cadavres de ces petites bestioles sont parsemés dans votre camp, pour la plus grande joie des paléontologues qui s'empressent d'en subtiliser quelques-uns pour les étudier. Les autres sont utilisés pour regarnir vos réserves de nourriture."
}
},
"ending": {
Expand Down Expand Up @@ -396,6 +396,6 @@
"game_over": {
"highscore": "Meilleur score : ",
"score": "Score : ",
"credits": "Jeu original développé par :\n\n- Paul Creusy\n- Clément Perrin\n- Balthazar Patiachvili\n- Alexis Guillon\n- Yohan Abehssera\n\nRemasterisé par :\n\n- Paul Creusy\n- Agathe Aris"
"credits": "Jeu original développé par :\n\n- Paul Creusy\n- Clément Perrin\n- Balthazar Patiachvili\n- Alexis Guillon\n- Yohan Abehssera\n\nRemastérisé par :\n\n- Paul Creusy\n- Agathe Aris"
}
}
113 changes: 98 additions & 15 deletions tools/game_tools/sound.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
### Imports ###
###############

### Python imports ###
from math import exp
from typing import Literal

from kivy.core.audio import SoundLoader
### Kivy imports ###
from kivy.core.audio import SoundLoader, Sound

### Local imports ###
from tools.constants import FPS


Expand All @@ -20,38 +24,65 @@

class MusicMixer():
"""
Classe destinée à gérer la musique dans le jeu
Une seule musique peut être jouée à la fois.
Class to play music, only one sound can be played at the time.
"""

def __init__(self, dict_music):
self.musics = dict_music

def change_volume(self, new_volume, name=None):
def change_volume(self, new_volume: float, name: str = None):
"""
Change the volume of a single sound or all the sounds.

Parameters
----------
new_volume : float
New volume to use.
name : str, optional
Name of the sound for which to change the volume, if None, applies to all the sounds,
by default None
"""
if name is not None:
self.musics[name].volume = new_volume
else:
for key in self.musics:
self.musics[key].volume = new_volume

def play(self, name, loop=False, timecode=0, stop_other_sounds=True):
def play(self, name: str, loop: bool = False, timecode: float = 0, stop_other_sounds: bool = True):
"""
Play the choosen sound.

Parameters
----------
name : str
Name of the sound to play.
loop : bool, optional
Boolean to trigger the loop of the sound, by default False
timecode : float, optional
Start timecode of the sound, by default 0
stop_other_sounds : bool, optional
Boolean to stop all other sound currently playing before playing the new sound, by default True
"""
if stop_other_sounds:
self.stop()
self.musics[name].play()
if timecode != 0:
# Ne marche pas
self.musics[name].seek(1)
# TODO: Does not work for now
self.musics[name].seek(timecode)
self.musics[name].loop = loop

def stop(self):
"""
Stop all sounds currently playing.
"""
for key in self.musics:
if self.musics[key].state == "play":
self.musics[key].stop()


class DynamicMusicMixer(MusicMixer):
"""
Classe destinée à jouer des bruitages sur lesquels on peut appliquer des effets en jeu.
Class to play sound effects and musics that require dynamic management.
"""

def __init__(self, dict_music, volume):
Expand All @@ -63,29 +94,62 @@ def __init__(self, dict_music, volume):
self.dico_frame_state = dico_frame_state
self.volume = volume

def add_sounds(self, sound_dict):
def add_sounds(self, sound_dict: dict):
"""
Add all sounds contained in a dictionnary to the mixer.

Parameters
----------
sound_dict : dict
Dictionnary containing the sounds to add.
"""
for sound_name in sound_dict:
self.dico_frame_state[sound_name] = 0
self.musics[sound_name] = sound_dict[sound_name]
self.musics[sound_name].volume = self.volume

def add_sound(self, sound, sound_name):
def add_sound(self, sound: Sound, sound_name: str):
"""
Add a new sound to the mixer

Parameters
----------
sound : Sound
Sound to add.
sound_name : str
Name of the sound to add.
"""
self.dico_frame_state[sound_name] = 0
self.musics[sound_name] = sound
self.musics[sound_name].volume = self.volume

def fade_out(self, name, duration, mode="linear"):
def fade_out(self, name: str, duration: float, mode: Literal["linear", "exp"] = "linear"):
"""
Apply a fade out effect to a sound

Parameters
----------
name : str
Name of the sound to fade out.
duration : float
Fade out duration in seconds.
mode : Literal["linear", "exp"], optional
Fade out mode, by default "linear"
"""
if mode == "exp":
self.instructions.append(("exp_fade_out", name, duration))
else:
self.instructions.append(("fade_out", name, duration))

def recursive_update(self):
"""
Update to call at each time unit of the screen to update the sound effects.
"""
pop_list = []
# Parcours des instructions à effectuer
# Iterate over the instructions to execute
for instruction in self.instructions:
new_volume = None
# Calcul de l'instruction
# Execute the instruction
if instruction[0] == "fade_out":
key, duration = instruction[1], instruction[2]
volume = self.musics[key].volume
Expand All @@ -98,7 +162,7 @@ def recursive_update(self):
t = 60 * self.dico_frame_state[key] / frame_to_fade
self.dico_frame_state[key] += 1
new_volume = exp_fade_out(t) * self.volume
# Application du changement de volume
# Apply the volume change
if new_volume is not None:
if new_volume > 0:
self.musics[key].volume = new_volume
Expand All @@ -108,7 +172,7 @@ def recursive_update(self):
self.musics[key].volume = self.volume
self.dico_frame_state[key] = 0
pop_list.append(instruction)
# Enlève les instructions terminées
# Remove executed instruction
for el in pop_list:
self.instructions.remove(el)

Expand All @@ -132,6 +196,14 @@ def __init__(self, dict_sound, volume, channel_number=10):
def play(self, name: str, volume: float = None):
"""
Play the selected sound.

Parameters
----------
name : str
Name of the sound to play.
volume : float, optional
Volume to use to play the sound, default volume if None,
by default None
"""
i = 0
while i < self.channel_number and self.sounds[name][i].state == "play":
Expand All @@ -144,6 +216,17 @@ def play(self, name: str, volume: float = None):
print("Unable to play the desired sound due to channel saturation")

def change_volume(self, new_volume: float, name: str = None):
"""
Change the volume of a single sound or all the sounds.

Parameters
----------
new_volume : float
New volume to use.
name : str, optional
Name of the sound for which to change the volume, if None, applies to all the sounds,
by default None
"""
if name is not None:
for i in range(self.channel_number):
self.sounds[name][i].volume = new_volume
Expand Down