Initial commit
This commit is contained in:
commit
778fe31c38
35 changed files with 1849 additions and 0 deletions
BIN
fugue1.mid
Normal file
BIN
fugue1.mid
Normal file
Binary file not shown.
11
level1.py
Normal file
11
level1.py
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
"""
|
||||||
|
Niveau 1
|
||||||
|
Jouer des sons
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synthlib, math
|
||||||
|
|
||||||
|
sound_encoder = synthlib.SoundEncoder()
|
||||||
|
for i in range(13):
|
||||||
|
for t in range(4000):
|
||||||
|
sound_encoder.write_sample(math.sin(t/16000*440*2**(i/12)*2*math.pi))
|
||||||
18
level2.py
Normal file
18
level2.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
"""
|
||||||
|
Niveau 2
|
||||||
|
Jouer une mélodie
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synthlib, math
|
||||||
|
|
||||||
|
music = [
|
||||||
|
(1, 0),
|
||||||
|
(1, 2),
|
||||||
|
(2, 4)
|
||||||
|
]
|
||||||
|
|
||||||
|
sound_encoder = synthlib.SoundEncoder()
|
||||||
|
for note in music:
|
||||||
|
for t in range(note[0]*4000):
|
||||||
|
sound_encoder.write_sample(math.sin(t/16000*440*2**(note[1]/12)*2*math.pi))
|
||||||
|
|
||||||
22
level3.py
Normal file
22
level3.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
"""
|
||||||
|
Niveau 3
|
||||||
|
Jouer des accords
|
||||||
|
|
||||||
|
Ne pas introduire le facteur d'amplitude avant d'avoir entendu le résultat sans lui
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synthlib, math
|
||||||
|
|
||||||
|
music = [
|
||||||
|
(1, [-9]),
|
||||||
|
(1, [-5]),
|
||||||
|
(1, [-2]),
|
||||||
|
(3, [-9, -5, -2])
|
||||||
|
]
|
||||||
|
|
||||||
|
sound_encoder = synthlib.SoundEncoder()
|
||||||
|
for note in music:
|
||||||
|
for t in range(note[0]*6000):
|
||||||
|
sound_encoder.write_sample(sum([0.3*math.sin(t/16000*440*2**(i/12)*2*math.pi) for i in note[1]]))
|
||||||
|
|
||||||
|
|
||||||
42
level4.py
Normal file
42
level4.py
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
"""
|
||||||
|
Niveau 4
|
||||||
|
Jouer des accords
|
||||||
|
|
||||||
|
Ne pas introduire le facteur d'amplitude avant d'avoir entendu le résultat sans lui
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synthlib, math, sys
|
||||||
|
|
||||||
|
music = synthlib.midi()
|
||||||
|
|
||||||
|
active = {}
|
||||||
|
wait = 0
|
||||||
|
tt = 0
|
||||||
|
t = 0
|
||||||
|
loop = True
|
||||||
|
|
||||||
|
sound_encoder = synthlib.SoundEncoder()
|
||||||
|
while loop:
|
||||||
|
if wait == 0:
|
||||||
|
while True:
|
||||||
|
event = music[tt]
|
||||||
|
tt += 1
|
||||||
|
if event.type == synthlib.Note:
|
||||||
|
if event.velocity == 0:
|
||||||
|
if event.number in active:
|
||||||
|
active.pop(event.number)
|
||||||
|
sys.stderr.write("pop "+str(event.number)+"\n")
|
||||||
|
else:
|
||||||
|
active[event.number] = event.velocity
|
||||||
|
sys.stderr.write(str(event.velocity)+" "+str(event.number)+" ("+str(len(active))+")\n")
|
||||||
|
elif event.type == synthlib.Wait:
|
||||||
|
wait = int(event.value*8000)
|
||||||
|
break
|
||||||
|
elif event.type == synthlib.End:
|
||||||
|
loop = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
wait -= 1
|
||||||
|
|
||||||
|
sound_encoder.write_sample(sum([active[number]*math.sin(t/16000*440*2**(number/12)*2*math.pi) for number in active])/max(1,len(active)))
|
||||||
|
t += 1
|
||||||
70
level5.py
Normal file
70
level5.py
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
"""
|
||||||
|
Niveau 5
|
||||||
|
Nouveaux instruments
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synthlib, math, sys
|
||||||
|
|
||||||
|
rate = 44100
|
||||||
|
|
||||||
|
def sine(t, f):
|
||||||
|
return math.sin(t/rate*f*2*math.pi)
|
||||||
|
|
||||||
|
def cosine(t, f):
|
||||||
|
return math.cosin(t/rate*f*2*math.pi)
|
||||||
|
|
||||||
|
def sine2(t, f):
|
||||||
|
return math.atan(math.sin(t/rate*f*2*math.pi))
|
||||||
|
|
||||||
|
def sine3(t, f):
|
||||||
|
return (sine(t,f) - sine2(t,f))*math.pi
|
||||||
|
|
||||||
|
def sine4(t, f):
|
||||||
|
return (cosine(t,f) - sine3(t,f))*2
|
||||||
|
|
||||||
|
polynome = [32, 30, 8, 4, 2, 1]
|
||||||
|
lpolynome = len(polynome)
|
||||||
|
spolynome = sum(polynome)
|
||||||
|
def polynomial(t, f):
|
||||||
|
return sum(j*math.sin(t/rate*f*2*math.pi*i) for i,j in enumerate(polynome)) / spolynome
|
||||||
|
|
||||||
|
music = synthlib.midi()
|
||||||
|
|
||||||
|
active = {}
|
||||||
|
wait = 0
|
||||||
|
tt = 0
|
||||||
|
t = 0
|
||||||
|
loop = True
|
||||||
|
|
||||||
|
sound_encoder = synthlib.SoundEncoder(env={
|
||||||
|
"sampling": rate,
|
||||||
|
"signed": True,
|
||||||
|
"verbose": False,
|
||||||
|
"bits": 32,
|
||||||
|
"msbfirst": True,
|
||||||
|
"tempo": 130
|
||||||
|
})
|
||||||
|
while loop:
|
||||||
|
if wait == 0:
|
||||||
|
while True:
|
||||||
|
event = music[tt]
|
||||||
|
tt += 1
|
||||||
|
if event.type == synthlib.Note:
|
||||||
|
if event.velocity == 0:
|
||||||
|
if event.number in active:
|
||||||
|
active.pop(event.number)
|
||||||
|
else:
|
||||||
|
active[event.number] = event.velocity
|
||||||
|
#sys.stderr.write(str(event.velocity)+"\n")
|
||||||
|
elif event.type == synthlib.Wait:
|
||||||
|
wait = int(event.value*rate/2)
|
||||||
|
break
|
||||||
|
elif event.type == synthlib.End:
|
||||||
|
loop = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
wait -= 1
|
||||||
|
|
||||||
|
sound_encoder.write_sample(sum([active[number]*polynomial(t, 440*2**(number/12)) for number in active])/max(1,len(active)))
|
||||||
|
t += 1
|
||||||
|
|
||||||
29
loop.py
Normal file
29
loop.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import synthlib, math, sys
|
||||||
|
|
||||||
|
rate = 44100
|
||||||
|
|
||||||
|
# freq is multiplied by factor every period
|
||||||
|
def sine(t, period, decay, factor, full_period):
|
||||||
|
tt = (t + decay) % full_period
|
||||||
|
if tt == 0:
|
||||||
|
volume = 0
|
||||||
|
elif tt <= full_period/2:
|
||||||
|
volume = tt/(full_period/2)
|
||||||
|
else:
|
||||||
|
volume = (full_period-tt)/(full_period/2)
|
||||||
|
freq_factor = 27.5*factor**(tt/period)
|
||||||
|
return volume**2*math.sin(tt*freq_factor/rate*2*math.pi)
|
||||||
|
|
||||||
|
nb = 3
|
||||||
|
|
||||||
|
sound_encoder = synthlib.SoundEncoder(env={
|
||||||
|
"sampling": rate,
|
||||||
|
"signed": True,
|
||||||
|
"verbose": False,
|
||||||
|
"bits": 32,
|
||||||
|
"msbfirst": True,
|
||||||
|
"tempo": 130
|
||||||
|
})
|
||||||
|
for t in range(rate*16):
|
||||||
|
sound_encoder.write_sample(sum([sine(t, rate, i*rate/nb*4, 2, rate*4) for i in range(nb)])/nb)
|
||||||
|
|
||||||
BIN
mario.mid
Normal file
BIN
mario.mid
Normal file
Binary file not shown.
13
pub/level1.py
Normal file
13
pub/level1.py
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
"""
|
||||||
|
Niveau 1
|
||||||
|
Jouer un son
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Permet d'utiliser les fonctions audio
|
||||||
|
import synth
|
||||||
|
|
||||||
|
# crée un encodeur audio
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
|
||||||
|
# écrit un échantillon
|
||||||
|
encoder.write(0)
|
||||||
8
pub/level2.py
Normal file
8
pub/level2.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
"""
|
||||||
|
Niveau 2
|
||||||
|
Jouer des notes
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
21
pub/level3.py
Normal file
21
pub/level3.py
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
"""
|
||||||
|
Niveau 3
|
||||||
|
Jouer une mélodie
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
|
||||||
|
# Liste de notes, sous la forme [durée, note]
|
||||||
|
music = [
|
||||||
|
[1, 4],
|
||||||
|
[1, 3],
|
||||||
|
[1, 4],
|
||||||
|
[1, 3],
|
||||||
|
[1, 4],
|
||||||
|
[1, -1],
|
||||||
|
[1, 2],
|
||||||
|
[1, 0],
|
||||||
|
[2, -3]
|
||||||
|
]
|
||||||
18
pub/level4.py
Normal file
18
pub/level4.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
"""
|
||||||
|
Niveau 4
|
||||||
|
Jouer des accords
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
|
||||||
|
# Liste d'accords, sous la forme [durée, [note, note, note, ...]]
|
||||||
|
music = [
|
||||||
|
[2, [5, 9]],
|
||||||
|
[2, [4, 8]],
|
||||||
|
[1, [-12]],
|
||||||
|
[1, [0, 2, 4]],
|
||||||
|
[1, [-10]],
|
||||||
|
[1, [2, 4, 6]],
|
||||||
|
]
|
||||||
13
pub/level5.py
Normal file
13
pub/level5.py
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
"""
|
||||||
|
Niveau 5
|
||||||
|
Jouer une partition
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
|
||||||
|
music = synth.Midi()
|
||||||
|
|
||||||
|
#for notes in music:
|
||||||
|
# notes est une liste dont les éléments sont [piste, note, force]
|
||||||
13
pub/level6.py
Normal file
13
pub/level6.py
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
"""
|
||||||
|
Niveau 6
|
||||||
|
Appliquer des filtres
|
||||||
|
* Écho : garder une copie du son et la jouer en décalé et moins fort
|
||||||
|
* Wah-wah : atténuer le son périodiquement
|
||||||
|
* Phaser : comme l'écho, mais en rejouant périodiquement des échantillons plus ou moins récents
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
|
||||||
|
music = synth.Midi()
|
||||||
237
pub/synth.py
Normal file
237
pub/synth.py
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import sys, os, subprocess, mido
|
||||||
|
|
||||||
|
def getarg(pos, default):
|
||||||
|
if len(sys.argv) > pos:
|
||||||
|
return sys.argv[pos]
|
||||||
|
return default
|
||||||
|
|
||||||
|
class Encoder:
|
||||||
|
def __init__(self, fp=None, fp_log=sys.stderr):
|
||||||
|
self.fp = fp if fp == None or fp.mode == "wb" else os.fdopen(fp.fileno(), 'wb')
|
||||||
|
self.fp_log = fp_log
|
||||||
|
|
||||||
|
self.sampling = 16000
|
||||||
|
self.signed = True
|
||||||
|
self.verbose = False
|
||||||
|
self.bits = 16
|
||||||
|
self.msbfirst = True
|
||||||
|
|
||||||
|
def write(self, amplitude):
|
||||||
|
if self.fp == None:
|
||||||
|
aplay = subprocess.Popen([
|
||||||
|
"aplay",
|
||||||
|
"-r",
|
||||||
|
str(self.sampling),
|
||||||
|
"-f",
|
||||||
|
("S" if self.signed else "U") + str(self.bits) + "_" + ("LE" if self.msbfirst else "BE")
|
||||||
|
], stdin=subprocess.PIPE, stderr=self.fp_log)
|
||||||
|
self.fp = aplay.stdin
|
||||||
|
|
||||||
|
smax = 2**(self.bits-self.signed)-1
|
||||||
|
if self.signed:
|
||||||
|
v = int(amplitude*smax)
|
||||||
|
w = v
|
||||||
|
s = v < 0
|
||||||
|
v = abs(v)
|
||||||
|
if s:
|
||||||
|
v = smax-v
|
||||||
|
v |= s << (self.bits-1)
|
||||||
|
else:
|
||||||
|
v = int((amplitude*smax+smax)/2)
|
||||||
|
w = v
|
||||||
|
|
||||||
|
if self.msbfirst:
|
||||||
|
i = 0
|
||||||
|
while i < self.bits:
|
||||||
|
if self.fp.write(bytes([(v>>i)&255])) > 1:
|
||||||
|
self.fp_log.write(str(v))
|
||||||
|
if self.verbose:
|
||||||
|
self.fp_log.write(bin((v>>i)&255)[2:].zfill(8))
|
||||||
|
i += 8
|
||||||
|
else:
|
||||||
|
i = self.bits
|
||||||
|
while i > 0:
|
||||||
|
i -= 8
|
||||||
|
self.fp.write(bytes([(v>>i)&255]))
|
||||||
|
if self.verbose:
|
||||||
|
self.fp_log.write(bin((v>>i)&255)[2:].zfill(8))
|
||||||
|
|
||||||
|
if self.verbose:
|
||||||
|
self.fp_log.write(" "+"0"*(self.bits-len(bin(v))+2)+bin(v)[2:]+" "+str(v)+" "+str(w)+"\n")
|
||||||
|
|
||||||
|
class Event:
|
||||||
|
def __init__(self, type):
|
||||||
|
self.type = type
|
||||||
|
|
||||||
|
class Wait(Event):
|
||||||
|
def __init__(self, value):
|
||||||
|
Event.__init__(self, Wait)
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"type": "wait",
|
||||||
|
"number": self.value,
|
||||||
|
}
|
||||||
|
|
||||||
|
class End(Event):
|
||||||
|
def __init__(self):
|
||||||
|
Event.__init__(self, End)
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"type": "end"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Note(Event):
|
||||||
|
def __init__(self, number, velocity, channel=0, track=0):
|
||||||
|
Event.__init__(self, Note)
|
||||||
|
self.number = number
|
||||||
|
self.velocity = velocity
|
||||||
|
self.channel = channel
|
||||||
|
self.track = track
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"type": "note",
|
||||||
|
"number": self.number,
|
||||||
|
"velocity": self.velocity,
|
||||||
|
"channel": self.channel
|
||||||
|
}
|
||||||
|
|
||||||
|
def midi_events():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
raise ValueError("Il faut donner le nom du fichier: python3 "+sys.argv[0]+" fichier.mid")
|
||||||
|
return read_midi(sys.argv[1], getarg(2, 130))
|
||||||
|
|
||||||
|
_midi = None
|
||||||
|
_midi_active = {}
|
||||||
|
_midi_wait = 0
|
||||||
|
_midi_tt = 0
|
||||||
|
_midi_loop = True
|
||||||
|
def midi2():
|
||||||
|
global _midi, _midi_active, _midi_wait, _midi_tt, _midi_loop
|
||||||
|
if _midi == None:
|
||||||
|
_midi = midi_events()
|
||||||
|
|
||||||
|
if _midi_loop:
|
||||||
|
if _midi_wait == 0:
|
||||||
|
while True:
|
||||||
|
event = _midi[_midi_tt]
|
||||||
|
_midi_tt += 1
|
||||||
|
if event.type == Note:
|
||||||
|
if event.velocity == 0:
|
||||||
|
if (event.number, event.track) in _midi_active:
|
||||||
|
_midi_active.pop((event.number, event.track))
|
||||||
|
else:
|
||||||
|
_midi_active[(event.number, event.track)] = event.velocity
|
||||||
|
elif event.type == Wait:
|
||||||
|
_midi_wait = int(event.value*8000)
|
||||||
|
break
|
||||||
|
elif event.type == End:
|
||||||
|
_midi_loop = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
_midi_wait -= 1
|
||||||
|
|
||||||
|
return [[idx[0], idx[1], _midi_active[idx]] for idx in _midi_active]
|
||||||
|
|
||||||
|
"""
|
||||||
|
Lit le fichier MIDI donné en argument de la commande.
|
||||||
|
Retourne, pour chaque échantillon, la liste des notes sous la forme [piste, note, amplitude].
|
||||||
|
"""
|
||||||
|
class Midi:
|
||||||
|
def __init__(self, sampling=16000):
|
||||||
|
self.sampling = sampling
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
self.active = {}
|
||||||
|
self.wait = 0
|
||||||
|
self.tt = 0
|
||||||
|
self.loop = True
|
||||||
|
self.events = midi_events()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self.loop:
|
||||||
|
if self.wait == 0:
|
||||||
|
while True:
|
||||||
|
event = self.events[self.tt]
|
||||||
|
self.tt += 1
|
||||||
|
if event.type == Note:
|
||||||
|
if event.velocity == 0:
|
||||||
|
if (event.track, event.number) in self.active:
|
||||||
|
self.active.pop((event.track, event.number))
|
||||||
|
else:
|
||||||
|
sys.stderr.write("Piste="+str(event.track)+" Note="+str(event.number)+" Force="+str(event.velocity)+"\n")
|
||||||
|
self.active[(event.track, event.number)] = event.velocity
|
||||||
|
elif event.type == Wait:
|
||||||
|
self.wait = int(event.value*self.sampling/2)
|
||||||
|
break
|
||||||
|
elif event.type == End:
|
||||||
|
self.loop = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.wait -= 1
|
||||||
|
|
||||||
|
return [[idx[0], idx[1], self.active[idx]] for idx in self.active]
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def read_midi(filename, tempo):
|
||||||
|
mid = mido.MidiFile(filename)
|
||||||
|
result = []
|
||||||
|
tracks = [0 for i in mid.tracks]
|
||||||
|
tempo = [tempo for i in mid.tracks]
|
||||||
|
wait = [None for i in mid.tracks]
|
||||||
|
end = [False for i in mid.tracks]
|
||||||
|
t = 0
|
||||||
|
loop = True
|
||||||
|
while loop:
|
||||||
|
loop = False
|
||||||
|
|
||||||
|
# Find the first events
|
||||||
|
first = []
|
||||||
|
firstt = None
|
||||||
|
for i, track in enumerate(mid.tracks):
|
||||||
|
if end[i]:
|
||||||
|
continue
|
||||||
|
if wait[i] == None:
|
||||||
|
wait[i] = track[tracks[i]].time/tempo[i]/4
|
||||||
|
|
||||||
|
if firstt == None or wait[i] < firstt:
|
||||||
|
firstt = wait[i]
|
||||||
|
first = [i]
|
||||||
|
elif wait[i] == firstt:
|
||||||
|
first.append(i)
|
||||||
|
|
||||||
|
if firstt > 0:
|
||||||
|
result.append(Wait(firstt))
|
||||||
|
|
||||||
|
# Play the first events
|
||||||
|
for i, track in enumerate(mid.tracks):
|
||||||
|
if end[i]:
|
||||||
|
continue
|
||||||
|
loop = True
|
||||||
|
msg = track[tracks[i]]
|
||||||
|
if i in first:
|
||||||
|
# Play event
|
||||||
|
if msg.type == "set_tempo":
|
||||||
|
tempo[i] = 6e7/msg.tempo
|
||||||
|
elif msg.type == "note_on":
|
||||||
|
result.append(Note(msg.note-50, msg.velocity/100, msg.channel, i))
|
||||||
|
elif msg.type == "end_of_track":
|
||||||
|
result.append(End())
|
||||||
|
end[i] = True
|
||||||
|
|
||||||
|
# Find next event
|
||||||
|
tracks[i] += 1
|
||||||
|
wait[i] = None
|
||||||
|
else:
|
||||||
|
wait[i] -= firstt
|
||||||
|
|
||||||
|
if not (False in end):
|
||||||
|
loop = False
|
||||||
|
|
||||||
|
return result
|
||||||
BIN
pub/tutorial.pdf
Normal file
BIN
pub/tutorial.pdf
Normal file
Binary file not shown.
BIN
reunion.mid
Normal file
BIN
reunion.mid
Normal file
Binary file not shown.
4
sheet
Normal file
4
sheet
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
Activer le son:
|
||||||
|
amixer set Master 1+ toggle
|
||||||
|
|
||||||
|
python level5.py tetris2.mid | aplay -r 44100 -f S32_LE
|
||||||
BIN
stage/__pycache__/synth.cpython-311.pyc
Normal file
BIN
stage/__pycache__/synth.cpython-311.pyc
Normal file
Binary file not shown.
11
stage/level1.py
Normal file
11
stage/level1.py
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
"""
|
||||||
|
Niveau 1
|
||||||
|
Jouer un son
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
for t in range(64000):
|
||||||
|
#encoder.write(math.sin(t/16000*400))
|
||||||
|
encoder.write(t/16000*400%1)
|
||||||
12
stage/level2.py
Normal file
12
stage/level2.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
"""
|
||||||
|
Niveau 2
|
||||||
|
Jouer des notes
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
import math
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
for note in range(13):
|
||||||
|
for t in range(16000):
|
||||||
|
encoder.write(math.sin(t/16000 * 220 * 2**(note/12) * 2*math.pi))
|
||||||
25
stage/level3.py
Normal file
25
stage/level3.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
"""
|
||||||
|
Niveau 3
|
||||||
|
Jouer une mélodie
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
import math
|
||||||
|
|
||||||
|
music = [
|
||||||
|
[1, 4],
|
||||||
|
[1, 3],
|
||||||
|
[1, 4],
|
||||||
|
[1, 3],
|
||||||
|
[1, 4],
|
||||||
|
[1, -1],
|
||||||
|
[1, 2],
|
||||||
|
[1, 0],
|
||||||
|
[2, -3]
|
||||||
|
]
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
for note in music:
|
||||||
|
for t in range(note[0]*3000):
|
||||||
|
encoder.write(math.sin(t/16000 * 440 * 2**(note[1]/12) * 2*math.pi))
|
||||||
|
|
||||||
25
stage/level4.py
Normal file
25
stage/level4.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
"""
|
||||||
|
Niveau 4
|
||||||
|
Jouer des accords
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
import math
|
||||||
|
|
||||||
|
music = [
|
||||||
|
[2, [5, 9]],
|
||||||
|
[2, [4, 8]],
|
||||||
|
[1, [-12]],
|
||||||
|
[1, [0, 2, 4]],
|
||||||
|
[1, [-10]],
|
||||||
|
[1, [2, 4, 6]],
|
||||||
|
]
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
|
||||||
|
for chord in music:
|
||||||
|
for t in range(chord[0]*4000):
|
||||||
|
total = 0
|
||||||
|
for note in chord[1]:
|
||||||
|
total = total + math.sin(t/16000 * 440 * 2**(note/12) * 2*math.pi)
|
||||||
|
encoder.write(total * 0.3)
|
||||||
27
stage/level5.py
Normal file
27
stage/level5.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
"""
|
||||||
|
Niveau 5
|
||||||
|
Jouer une partition
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
import math
|
||||||
|
|
||||||
|
music = synth.Midi(32000)
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
encoder.sampling = 32000
|
||||||
|
|
||||||
|
instruments = [
|
||||||
|
lambda t, f: math.sin(t * f * 2*math.pi),
|
||||||
|
lambda t, f: math.sin(t * f * 2*math.pi) + math.sin(t * f * 4*math.pi)/2,
|
||||||
|
lambda t, f: math.sin(t * f * 2*math.pi) + math.sin(t * f * 4*math.pi)/2,
|
||||||
|
lambda t, f: t * f % 1 - 0.5,
|
||||||
|
]
|
||||||
|
|
||||||
|
t = 0
|
||||||
|
for notes in music:
|
||||||
|
total = 0
|
||||||
|
for note in notes:
|
||||||
|
total = total + instruments[note[0]](t/32000, 440 * 2**(note[1]/12)) * note[2]
|
||||||
|
encoder.write(total * 0.3)
|
||||||
|
t = t + 1
|
||||||
48
stage/level6.py
Normal file
48
stage/level6.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
"""
|
||||||
|
Niveau 6
|
||||||
|
Filtre audio
|
||||||
|
"""
|
||||||
|
|
||||||
|
import synth
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
|
||||||
|
music = synth.Midi(32000)
|
||||||
|
|
||||||
|
encoder = synth.Encoder()
|
||||||
|
encoder.sampling = 32000
|
||||||
|
|
||||||
|
instruments = [
|
||||||
|
lambda t, f: round(math.sin(t * f * 2*math.pi)) + random.random() * 0.3,
|
||||||
|
lambda t, f: math.sin(t * f * 2*math.pi),
|
||||||
|
lambda t, f: math.sin(t * f * 2*math.pi)*0.6 + math.sin(t * f * 4*math.pi)*0.3 + math.sin(t * f * 8*math.pi)*0.1,
|
||||||
|
lambda t, f: math.sin(t * f * 2*math.pi) + math.sin(t * f * 4*math.pi)/2,
|
||||||
|
lambda t, f: t * f % 1 - 0.5,
|
||||||
|
]
|
||||||
|
|
||||||
|
delay1 = [0] * 1000
|
||||||
|
delay2 = [0] * 3000
|
||||||
|
delay3 = [0] * 5000
|
||||||
|
phaser = [0] * 50
|
||||||
|
|
||||||
|
t = 0
|
||||||
|
for notes in music:
|
||||||
|
total = 0
|
||||||
|
for note in notes:
|
||||||
|
total = total + instruments[note[0]](t/32000, 440 * 2**(note[1]/12)) * note[2]
|
||||||
|
|
||||||
|
total = total * (math.sin(t/32000 * 20 * 2*math.pi)/8+7/8)
|
||||||
|
total += delay1.pop(0) * 0.1
|
||||||
|
total += delay2.pop(0) * 0.3
|
||||||
|
total += delay3.pop(0) * 0.4
|
||||||
|
delay1.append(total)
|
||||||
|
delay2.append(total)
|
||||||
|
delay3.append(total)
|
||||||
|
|
||||||
|
lfo = math.sin(t/32000 * 0.2 * 2*math.pi)
|
||||||
|
phaser.append(total)
|
||||||
|
phaser.pop(0)
|
||||||
|
total += phaser[int((lfo/2+0.5)*(len(phaser)-1))]
|
||||||
|
|
||||||
|
encoder.write(total * 0.1)
|
||||||
|
t = t + 1
|
||||||
237
stage/synth.py
Normal file
237
stage/synth.py
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import sys, os, subprocess, mido
|
||||||
|
|
||||||
|
def getarg(pos, default):
|
||||||
|
if len(sys.argv) > pos:
|
||||||
|
return sys.argv[pos]
|
||||||
|
return default
|
||||||
|
|
||||||
|
class Encoder:
|
||||||
|
def __init__(self, fp=None, fp_log=sys.stderr):
|
||||||
|
self.fp = fp if fp == None or fp.mode == "wb" else os.fdopen(fp.fileno(), 'wb')
|
||||||
|
self.fp_log = fp_log
|
||||||
|
|
||||||
|
self.sampling = 16000
|
||||||
|
self.signed = True
|
||||||
|
self.verbose = False
|
||||||
|
self.bits = 16
|
||||||
|
self.msbfirst = True
|
||||||
|
|
||||||
|
def write(self, amplitude):
|
||||||
|
if self.fp == None:
|
||||||
|
aplay = subprocess.Popen([
|
||||||
|
"aplay",
|
||||||
|
"-r",
|
||||||
|
str(self.sampling),
|
||||||
|
"-f",
|
||||||
|
("S" if self.signed else "U") + str(self.bits) + "_" + ("LE" if self.msbfirst else "BE")
|
||||||
|
], stdin=subprocess.PIPE, stderr=self.fp_log)
|
||||||
|
self.fp = aplay.stdin
|
||||||
|
|
||||||
|
smax = 2**(self.bits-self.signed)-1
|
||||||
|
if self.signed:
|
||||||
|
v = int(amplitude*smax)
|
||||||
|
w = v
|
||||||
|
s = v < 0
|
||||||
|
v = abs(v)
|
||||||
|
if s:
|
||||||
|
v = smax-v
|
||||||
|
v |= s << (self.bits-1)
|
||||||
|
else:
|
||||||
|
v = int((amplitude*smax+smax)/2)
|
||||||
|
w = v
|
||||||
|
|
||||||
|
if self.msbfirst:
|
||||||
|
i = 0
|
||||||
|
while i < self.bits:
|
||||||
|
if self.fp.write(bytes([(v>>i)&255])) > 1:
|
||||||
|
self.fp_log.write(str(v))
|
||||||
|
if self.verbose:
|
||||||
|
self.fp_log.write(bin((v>>i)&255)[2:].zfill(8))
|
||||||
|
i += 8
|
||||||
|
else:
|
||||||
|
i = self.bits
|
||||||
|
while i > 0:
|
||||||
|
i -= 8
|
||||||
|
self.fp.write(bytes([(v>>i)&255]))
|
||||||
|
if self.verbose:
|
||||||
|
self.fp_log.write(bin((v>>i)&255)[2:].zfill(8))
|
||||||
|
|
||||||
|
if self.verbose:
|
||||||
|
self.fp_log.write(" "+"0"*(self.bits-len(bin(v))+2)+bin(v)[2:]+" "+str(v)+" "+str(w)+"\n")
|
||||||
|
|
||||||
|
class Event:
|
||||||
|
def __init__(self, type):
|
||||||
|
self.type = type
|
||||||
|
|
||||||
|
class Wait(Event):
|
||||||
|
def __init__(self, value):
|
||||||
|
Event.__init__(self, Wait)
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"type": "wait",
|
||||||
|
"number": self.value,
|
||||||
|
}
|
||||||
|
|
||||||
|
class End(Event):
|
||||||
|
def __init__(self):
|
||||||
|
Event.__init__(self, End)
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"type": "end"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Note(Event):
|
||||||
|
def __init__(self, number, velocity, channel=0, track=0):
|
||||||
|
Event.__init__(self, Note)
|
||||||
|
self.number = number
|
||||||
|
self.velocity = velocity
|
||||||
|
self.channel = channel
|
||||||
|
self.track = track
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"type": "note",
|
||||||
|
"number": self.number,
|
||||||
|
"velocity": self.velocity,
|
||||||
|
"channel": self.channel
|
||||||
|
}
|
||||||
|
|
||||||
|
def midi_events():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
raise ValueError("Il faut donner le nom du fichier: python3 "+sys.argv[0]+" fichier.mid")
|
||||||
|
return read_midi(sys.argv[1], float(getarg(2, 80)))
|
||||||
|
|
||||||
|
_midi = None
|
||||||
|
_midi_active = {}
|
||||||
|
_midi_wait = 0
|
||||||
|
_midi_tt = 0
|
||||||
|
_midi_loop = True
|
||||||
|
def midi2():
|
||||||
|
global _midi, _midi_active, _midi_wait, _midi_tt, _midi_loop
|
||||||
|
if _midi == None:
|
||||||
|
_midi = midi_events()
|
||||||
|
|
||||||
|
if _midi_loop:
|
||||||
|
if _midi_wait == 0:
|
||||||
|
while True:
|
||||||
|
event = _midi[_midi_tt]
|
||||||
|
_midi_tt += 1
|
||||||
|
if event.type == Note:
|
||||||
|
if event.velocity == 0:
|
||||||
|
if (event.number, event.track) in _midi_active:
|
||||||
|
_midi_active.pop((event.number, event.track))
|
||||||
|
else:
|
||||||
|
_midi_active[(event.number, event.track)] = event.velocity
|
||||||
|
elif event.type == Wait:
|
||||||
|
_midi_wait = int(event.value*8000)
|
||||||
|
break
|
||||||
|
elif event.type == End:
|
||||||
|
_midi_loop = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
_midi_wait -= 1
|
||||||
|
|
||||||
|
return [[idx[0], idx[1], _midi_active[idx]] for idx in _midi_active]
|
||||||
|
|
||||||
|
"""
|
||||||
|
Lit le fichier MIDI donné en argument de la commande.
|
||||||
|
Retourne, pour chaque échantillon, la liste des notes sous la forme [piste, note, amplitude].
|
||||||
|
"""
|
||||||
|
class Midi:
|
||||||
|
def __init__(self, sampling=16000):
|
||||||
|
self.sampling = sampling
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
self.active = {}
|
||||||
|
self.wait = 0
|
||||||
|
self.tt = 0
|
||||||
|
self.loop = True
|
||||||
|
self.events = midi_events()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self.loop:
|
||||||
|
if self.wait == 0:
|
||||||
|
while True:
|
||||||
|
event = self.events[self.tt]
|
||||||
|
self.tt += 1
|
||||||
|
if event.type == Note:
|
||||||
|
if event.velocity == 0:
|
||||||
|
if (event.track, event.number) in self.active:
|
||||||
|
self.active.pop((event.track, event.number))
|
||||||
|
else:
|
||||||
|
sys.stderr.write("Piste="+str(event.track)+" Note="+str(event.number)+" Force="+str(event.velocity)+"\n")
|
||||||
|
self.active[(event.track, event.number)] = event.velocity
|
||||||
|
elif event.type == Wait:
|
||||||
|
self.wait = int(event.value*self.sampling/2)
|
||||||
|
break
|
||||||
|
elif event.type == End:
|
||||||
|
self.loop = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.wait -= 1
|
||||||
|
|
||||||
|
return [[idx[0], idx[1], self.active[idx]] for idx in self.active]
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def read_midi(filename, tempo):
|
||||||
|
mid = mido.MidiFile(filename)
|
||||||
|
result = []
|
||||||
|
tracks = [0 for i in mid.tracks]
|
||||||
|
tempo = [tempo for i in mid.tracks]
|
||||||
|
wait = [None for i in mid.tracks]
|
||||||
|
end = [False for i in mid.tracks]
|
||||||
|
t = 0
|
||||||
|
loop = True
|
||||||
|
while loop:
|
||||||
|
loop = False
|
||||||
|
|
||||||
|
# Find the first events
|
||||||
|
first = []
|
||||||
|
firstt = None
|
||||||
|
for i, track in enumerate(mid.tracks):
|
||||||
|
if end[i]:
|
||||||
|
continue
|
||||||
|
if wait[i] == None:
|
||||||
|
wait[i] = track[tracks[i]].time/tempo[i]/4
|
||||||
|
|
||||||
|
if firstt == None or wait[i] < firstt:
|
||||||
|
firstt = wait[i]
|
||||||
|
first = [i]
|
||||||
|
elif wait[i] == firstt:
|
||||||
|
first.append(i)
|
||||||
|
|
||||||
|
if firstt > 0:
|
||||||
|
result.append(Wait(firstt))
|
||||||
|
|
||||||
|
# Play the first events
|
||||||
|
for i, track in enumerate(mid.tracks):
|
||||||
|
if end[i]:
|
||||||
|
continue
|
||||||
|
loop = True
|
||||||
|
msg = track[tracks[i]]
|
||||||
|
if i in first:
|
||||||
|
# Play event
|
||||||
|
if msg.type == "set_tempo":
|
||||||
|
tempo[i] = 6e7/msg.tempo
|
||||||
|
elif msg.type == "note_on":
|
||||||
|
result.append(Note(msg.note-50, msg.velocity/100, msg.channel, i))
|
||||||
|
elif msg.type == "end_of_track":
|
||||||
|
result.append(End())
|
||||||
|
end[i] = True
|
||||||
|
|
||||||
|
# Find next event
|
||||||
|
tracks[i] += 1
|
||||||
|
wait[i] = None
|
||||||
|
else:
|
||||||
|
wait[i] -= firstt
|
||||||
|
|
||||||
|
if not (False in end):
|
||||||
|
loop = False
|
||||||
|
|
||||||
|
return result
|
||||||
246
synthlib.py
Normal file
246
synthlib.py
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import sys, os, mido
|
||||||
|
|
||||||
|
DEFAULT_ENV = {
|
||||||
|
"sampling": 16000,
|
||||||
|
"signed": True,
|
||||||
|
"verbose": False,
|
||||||
|
"bits": 16,
|
||||||
|
"msbfirst": True,
|
||||||
|
"tempo": 130
|
||||||
|
}
|
||||||
|
|
||||||
|
FP = sys.stdout
|
||||||
|
|
||||||
|
class SoundEncoder:
|
||||||
|
def __init__(self, env=DEFAULT_ENV, fp=sys.stdout, fp_log=sys.stderr):
|
||||||
|
self.env = env
|
||||||
|
self.fp = fp if fp.mode == "wb" else os.fdopen(fp.fileno(), 'wb')
|
||||||
|
self.fp_log = fp_log
|
||||||
|
|
||||||
|
def write_sample(self, amplitude):
|
||||||
|
smax = 2**(self.env["bits"]-self.env["signed"])-1
|
||||||
|
if self.env["signed"]:
|
||||||
|
v = int(amplitude*smax)
|
||||||
|
w = v
|
||||||
|
s = v < 0
|
||||||
|
v = abs(v)
|
||||||
|
if s:
|
||||||
|
v = smax-v
|
||||||
|
v |= (s<<(self.env["bits"]-1))
|
||||||
|
else:
|
||||||
|
v = int((amplitude*smax+smax)/2)
|
||||||
|
w = v
|
||||||
|
|
||||||
|
if self.env["msbfirst"]:
|
||||||
|
i = 0
|
||||||
|
while i < self.env["bits"]:
|
||||||
|
if self.fp.write(bytes([(v>>i)&255])) > 1:
|
||||||
|
self.fp_log.write(str(v))
|
||||||
|
b = bin((v>>i)&255)[2:]
|
||||||
|
if self.env["verbose"]:
|
||||||
|
self.fp_log.write("0"*(8-len(b))+b)
|
||||||
|
i += 8
|
||||||
|
else:
|
||||||
|
i = self.env["bits"]
|
||||||
|
while i > 0:
|
||||||
|
i -= 8
|
||||||
|
self.fp.write(bytes([(v>>i)&255]))
|
||||||
|
b = bin((v>>i)&255)[2:]
|
||||||
|
if self.env["verbose"]:
|
||||||
|
self.fp_log.write("0"*(8-len(b))+b)
|
||||||
|
|
||||||
|
if self.env["verbose"]:
|
||||||
|
self.fp_log.write(" "+"0"*(self.env["bits"]-len(bin(v))+2)+bin(v)[2:]+" "+str(v)+" "+str(w)+"\n")
|
||||||
|
|
||||||
|
class Event:
|
||||||
|
def __init__(self, type):
|
||||||
|
self.type = type
|
||||||
|
|
||||||
|
class Wait(Event):
|
||||||
|
def __init__(self, value):
|
||||||
|
Event.__init__(self, Wait)
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"type": "wait",
|
||||||
|
"number": self.value,
|
||||||
|
}
|
||||||
|
|
||||||
|
class End(Event):
|
||||||
|
def __init__(self):
|
||||||
|
Event.__init__(self, End)
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"type": "end"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Note(Event):
|
||||||
|
def __init__(self, number, velocity, channel=0, track=0):
|
||||||
|
Event.__init__(self, Note)
|
||||||
|
self.number = number
|
||||||
|
self.velocity = velocity
|
||||||
|
self.channel = channel
|
||||||
|
self.track = track
|
||||||
|
|
||||||
|
def dict(self):
|
||||||
|
return {
|
||||||
|
"type": "note",
|
||||||
|
"number": self.number,
|
||||||
|
"velocity": self.velocity,
|
||||||
|
"channel": self.channel
|
||||||
|
}
|
||||||
|
|
||||||
|
def midi():
|
||||||
|
return from_midi3(sys.argv[1])
|
||||||
|
|
||||||
|
def from_midi(filename, env=DEFAULT_ENV):
|
||||||
|
result = []
|
||||||
|
t = 0
|
||||||
|
tempo = env["tempo"]
|
||||||
|
mid = mido.MidiFile(filename)
|
||||||
|
for i, track in enumerate(mid.tracks):
|
||||||
|
for msg in track:
|
||||||
|
if msg.type == "set_tempo":
|
||||||
|
tempo = 6e7/msg.tempo
|
||||||
|
elif msg.type == "note_on":
|
||||||
|
if msg.time != 0:
|
||||||
|
result.append(Wait(msg.time/tempo/4))
|
||||||
|
result.append(Note(msg.note-50, msg.velocity/100, msg.channel))
|
||||||
|
elif msg.type == "end_of_track":
|
||||||
|
result.append(Wait(msg.time/tempo/4))
|
||||||
|
result.append(End())
|
||||||
|
return result
|
||||||
|
|
||||||
|
def from_midi2(filename, env=DEFAULT_ENV):
|
||||||
|
mid = mido.MidiFile(filename)
|
||||||
|
result = []
|
||||||
|
tracks = [0 for i in mid.tracks]
|
||||||
|
tempos = [env["tempo"] for i in mid.tracks]
|
||||||
|
wait = [None for i in mid.tracks]
|
||||||
|
end = [True for i in mid.tracks]
|
||||||
|
t = 0
|
||||||
|
loop = True
|
||||||
|
while loop:
|
||||||
|
loop = False
|
||||||
|
for i, track in enumerate(mid.tracks):
|
||||||
|
if end[i]:
|
||||||
|
loop = True
|
||||||
|
continue
|
||||||
|
if wait[i] == None:
|
||||||
|
wait[i] = track[tracks[i]].time/tempos[i]/4
|
||||||
|
#result.append(Wait(track[tracks[i]].time/tempo/4))
|
||||||
|
if wait[i] <= 0:
|
||||||
|
msg = track[tracks[i]]
|
||||||
|
if t > 0:
|
||||||
|
result.append(Wait(t))
|
||||||
|
t = 0
|
||||||
|
if msg.type == "set_tempo":
|
||||||
|
tempos[i] = 6e7/msg.tempo
|
||||||
|
elif msg.type == "note_on":
|
||||||
|
result.append(Note(msg.note-50, msg.velocity/100, msg.channel, i))
|
||||||
|
elif msg.type == "end_of_track":
|
||||||
|
result.append(End())
|
||||||
|
end[i] = False
|
||||||
|
tracks[i] += 1
|
||||||
|
if len(track) > tracks[i]:
|
||||||
|
wait[i] = track[tracks[i]].time/tempos[i]/4
|
||||||
|
|
||||||
|
else:
|
||||||
|
wait[i] -= 1
|
||||||
|
|
||||||
|
print(t)
|
||||||
|
t += 1
|
||||||
|
print(result)
|
||||||
|
exit()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def from_midi3(filename, env=DEFAULT_ENV):
|
||||||
|
mid = mido.MidiFile(filename)
|
||||||
|
result = []
|
||||||
|
tracks = [0 for i in mid.tracks]
|
||||||
|
tempo = [env["tempo"] for i in mid.tracks]
|
||||||
|
wait = [None for i in mid.tracks]
|
||||||
|
end = [False for i in mid.tracks]
|
||||||
|
t = 0
|
||||||
|
loop = True
|
||||||
|
while loop:
|
||||||
|
loop = False
|
||||||
|
|
||||||
|
# Find the first events
|
||||||
|
first = []
|
||||||
|
firstt = None
|
||||||
|
for i, track in enumerate(mid.tracks):
|
||||||
|
if end[i]:
|
||||||
|
continue
|
||||||
|
if wait[i] == None:
|
||||||
|
wait[i] = track[tracks[i]].time/tempo[i]/4
|
||||||
|
|
||||||
|
if firstt == None or wait[i] < firstt:
|
||||||
|
firstt = wait[i]
|
||||||
|
first = [i]
|
||||||
|
elif wait[i] == firstt:
|
||||||
|
first.append(i)
|
||||||
|
|
||||||
|
if firstt > 0:
|
||||||
|
result.append(Wait(firstt))
|
||||||
|
|
||||||
|
# Play the first events
|
||||||
|
for i, track in enumerate(mid.tracks):
|
||||||
|
if end[i]:
|
||||||
|
continue
|
||||||
|
loop = True
|
||||||
|
msg = track[tracks[i]]
|
||||||
|
if i in first:
|
||||||
|
# Play event
|
||||||
|
if msg.type == "set_tempo":
|
||||||
|
tempo[i] = 6e7/msg.tempo
|
||||||
|
elif msg.type == "note_on":
|
||||||
|
result.append(Note(msg.note-50, msg.velocity/100, msg.channel, i))
|
||||||
|
elif msg.type == "end_of_track":
|
||||||
|
result.append(End())
|
||||||
|
end[i] = True
|
||||||
|
|
||||||
|
# Find next event
|
||||||
|
tracks[i] += 1
|
||||||
|
wait[i] = None
|
||||||
|
else:
|
||||||
|
wait[i] -= firstt
|
||||||
|
|
||||||
|
if not (False in end):
|
||||||
|
loop = False
|
||||||
|
|
||||||
|
###
|
||||||
|
"""loop = False
|
||||||
|
for i, track in enumerate(mid.tracks):
|
||||||
|
if end[i]:
|
||||||
|
loop = True
|
||||||
|
continue
|
||||||
|
if wait[i] == None:
|
||||||
|
wait[i] = track[tracks[i]].time/tempo[i]/4
|
||||||
|
#result.append(Wait(track[tracks[i]].time/tempo/4))
|
||||||
|
if wait[i] <= 0:
|
||||||
|
msg = track[tracks[i]]
|
||||||
|
if t > 0:
|
||||||
|
result.append(Wait(t))
|
||||||
|
t = 0
|
||||||
|
if msg.type == "set_tempo":
|
||||||
|
tempo[i] = 6e7/msg.tempo
|
||||||
|
elif msg.type == "note_on":
|
||||||
|
result.append(Note(msg.note-50, msg.velocity/100, msg.channel, i))
|
||||||
|
elif msg.type == "end_of_track":
|
||||||
|
result.append(End())
|
||||||
|
end[i] = False
|
||||||
|
tracks[i] += 1
|
||||||
|
if len(track) > tracks[i]:
|
||||||
|
wait[i] = track[tracks[i]].time/tempo[i]/4
|
||||||
|
|
||||||
|
else:
|
||||||
|
wait[i] -= 1
|
||||||
|
|
||||||
|
print(t)
|
||||||
|
t += 1"""
|
||||||
|
return result
|
||||||
BIN
test2.mid
Normal file
BIN
test2.mid
Normal file
Binary file not shown.
BIN
tetris2.mid
Normal file
BIN
tetris2.mid
Normal file
Binary file not shown.
7
tuto/makefile
Executable file
7
tuto/makefile
Executable file
|
|
@ -0,0 +1,7 @@
|
||||||
|
all: tutorial.pdf
|
||||||
|
|
||||||
|
tutorial.pdf: tutorial.html
|
||||||
|
wkhtmltopdf -s A4 --footer-center "[page] / [topage]" --footer-font-name "Libertinus Sans" --footer-font-size 11 --header-left "[subsection]" --header-right "[title] par Pascal Engélibert, 2025, CC BY-SA 4.0" --header-font-name "Libertinus Sans" --header-font-size 11 --margin-top 20mm --footer-spacing 7 --header-spacing 7 --margin-bottom 20mm tutorial.html tutorial.pdf
|
||||||
|
|
||||||
|
tutorial.html: tutorial.md tutorial-head.html
|
||||||
|
pandoc tutorial.md -o tutorial.html --self-contained -M title="Tutoriel Python" --highlight-style pygments -H tutorial-head.html || exit 1
|
||||||
33
tuto/tutorial-head.html
Normal file
33
tuto/tutorial-head.html
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
font-family: "Libertinus Sans";
|
||||||
|
max-width: 80% !important;
|
||||||
|
font-size: 13pt !important;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
border-bottom: 2pt solid black;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
border-bottom: 1pt solid black;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
border-bottom: 1pt solid #ccc;
|
||||||
|
}
|
||||||
|
div.sourceCode {
|
||||||
|
margin-left: -5px;
|
||||||
|
border-left: 1px dashed #ccc;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
div.sourceCode code {
|
||||||
|
font-size: 10pt !important;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
font-family: "Fira Code" !important;
|
||||||
|
}
|
||||||
|
p code {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
margin-top: 1cm;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
427
tuto/tutorial.html
Normal file
427
tuto/tutorial.html
Normal file
|
|
@ -0,0 +1,427 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="generator" content="pandoc" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||||
|
<title>Tutoriel Python</title>
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
line-height: 1.5;
|
||||||
|
font-family: Georgia, serif;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #1a1a1a;
|
||||||
|
background-color: #fdfdfd;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 36em;
|
||||||
|
padding-left: 50px;
|
||||||
|
padding-right: 50px;
|
||||||
|
padding-top: 50px;
|
||||||
|
padding-bottom: 50px;
|
||||||
|
hyphens: auto;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
font-kerning: normal;
|
||||||
|
}
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 1.8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media print {
|
||||||
|
body {
|
||||||
|
background-color: transparent;
|
||||||
|
color: black;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
p, h2, h3 {
|
||||||
|
orphans: 3;
|
||||||
|
widows: 3;
|
||||||
|
}
|
||||||
|
h2, h3, h4 {
|
||||||
|
page-break-after: avoid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 1.4em;
|
||||||
|
}
|
||||||
|
h5, h6 {
|
||||||
|
font-size: 1em;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
h6 {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
padding-left: 1.7em;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
li > ol, li > ul {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
blockquote {
|
||||||
|
margin: 1em 0 1em 1.7em;
|
||||||
|
padding-left: 1em;
|
||||||
|
border-left: 2px solid #e6e6e6;
|
||||||
|
color: #606060;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
font-family: Menlo, Monaco, 'Lucida Console', Consolas, monospace;
|
||||||
|
font-size: 85%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
margin: 1em 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
pre code {
|
||||||
|
padding: 0;
|
||||||
|
overflow: visible;
|
||||||
|
overflow-wrap: normal;
|
||||||
|
}
|
||||||
|
.sourceCode {
|
||||||
|
background-color: transparent;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
margin: 1em 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
display: block;
|
||||||
|
font-variant-numeric: lining-nums tabular-nums;
|
||||||
|
}
|
||||||
|
table caption {
|
||||||
|
margin-bottom: 0.75em;
|
||||||
|
}
|
||||||
|
tbody {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
border-top: 1px solid #1a1a1a;
|
||||||
|
border-bottom: 1px solid #1a1a1a;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
border-top: 1px solid #1a1a1a;
|
||||||
|
padding: 0.25em 0.5em 0.25em 0.5em;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
padding: 0.125em 0.5em 0.25em 0.5em;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
margin-bottom: 4em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#TOC li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
#TOC ul {
|
||||||
|
padding-left: 1.3em;
|
||||||
|
}
|
||||||
|
#TOC > ul {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
#TOC a:not(:hover) {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
code{white-space: pre-wrap;}
|
||||||
|
span.smallcaps{font-variant: small-caps;}
|
||||||
|
span.underline{text-decoration: underline;}
|
||||||
|
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
||||||
|
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||||||
|
ul.task-list{list-style: none;}
|
||||||
|
pre > code.sourceCode { white-space: pre; position: relative; }
|
||||||
|
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
||||||
|
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||||||
|
.sourceCode { overflow: visible; }
|
||||||
|
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||||||
|
div.sourceCode { margin: 1em 0; }
|
||||||
|
pre.sourceCode { margin: 0; }
|
||||||
|
@media screen {
|
||||||
|
div.sourceCode { overflow: auto; }
|
||||||
|
}
|
||||||
|
@media print {
|
||||||
|
pre > code.sourceCode { white-space: pre-wrap; }
|
||||||
|
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
||||||
|
}
|
||||||
|
pre.numberSource code
|
||||||
|
{ counter-reset: source-line 0; }
|
||||||
|
pre.numberSource code > span
|
||||||
|
{ position: relative; left: -4em; counter-increment: source-line; }
|
||||||
|
pre.numberSource code > span > a:first-child::before
|
||||||
|
{ content: counter(source-line);
|
||||||
|
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||||||
|
border: none; display: inline-block;
|
||||||
|
-webkit-touch-callout: none; -webkit-user-select: none;
|
||||||
|
-khtml-user-select: none; -moz-user-select: none;
|
||||||
|
-ms-user-select: none; user-select: none;
|
||||||
|
padding: 0 4px; width: 4em;
|
||||||
|
color: #aaaaaa;
|
||||||
|
}
|
||||||
|
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
||||||
|
div.sourceCode
|
||||||
|
{ }
|
||||||
|
@media screen {
|
||||||
|
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||||||
|
}
|
||||||
|
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
||||||
|
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
||||||
|
code span.at { color: #7d9029; } /* Attribute */
|
||||||
|
code span.bn { color: #40a070; } /* BaseN */
|
||||||
|
code span.bu { color: #008000; } /* BuiltIn */
|
||||||
|
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
||||||
|
code span.ch { color: #4070a0; } /* Char */
|
||||||
|
code span.cn { color: #880000; } /* Constant */
|
||||||
|
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
||||||
|
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
||||||
|
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
||||||
|
code span.dt { color: #902000; } /* DataType */
|
||||||
|
code span.dv { color: #40a070; } /* DecVal */
|
||||||
|
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
||||||
|
code span.ex { } /* Extension */
|
||||||
|
code span.fl { color: #40a070; } /* Float */
|
||||||
|
code span.fu { color: #06287e; } /* Function */
|
||||||
|
code span.im { color: #008000; font-weight: bold; } /* Import */
|
||||||
|
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
||||||
|
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
||||||
|
code span.op { color: #666666; } /* Operator */
|
||||||
|
code span.ot { color: #007020; } /* Other */
|
||||||
|
code span.pp { color: #bc7a00; } /* Preprocessor */
|
||||||
|
code span.sc { color: #4070a0; } /* SpecialChar */
|
||||||
|
code span.ss { color: #bb6688; } /* SpecialString */
|
||||||
|
code span.st { color: #4070a0; } /* String */
|
||||||
|
code span.va { color: #19177c; } /* Variable */
|
||||||
|
code span.vs { color: #4070a0; } /* VerbatimString */
|
||||||
|
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
||||||
|
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
|
||||||
|
</style>
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
font-family: "Libertinus Sans";
|
||||||
|
max-width: 80% !important;
|
||||||
|
font-size: 13pt !important;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
border-bottom: 2pt solid black;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
border-bottom: 1pt solid black;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
border-bottom: 1pt solid #ccc;
|
||||||
|
}
|
||||||
|
div.sourceCode {
|
||||||
|
margin-left: -5px;
|
||||||
|
border-left: 1px dashed #ccc;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
div.sourceCode code {
|
||||||
|
font-size: 10pt !important;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
font-family: "Fira Code" !important;
|
||||||
|
}
|
||||||
|
p code {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
margin-top: 1cm;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header id="title-block-header">
|
||||||
|
<h1 class="title">Tutoriel Python</h1>
|
||||||
|
</header>
|
||||||
|
<h1 id="tutoriel-python">Tutoriel Python</h1>
|
||||||
|
<h2 id="terminal">Terminal</h2>
|
||||||
|
<p>Ouvrir un terminal : CTRL+ALT+T ou le bouton noir en bas de
|
||||||
|
l’écran.</p>
|
||||||
|
<p>Commandes :</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>ls</code> : <strong>l</strong>i<strong>s</strong>ter les
|
||||||
|
fichiers et dossiers</li>
|
||||||
|
<li><code>cd mondossier</code> : <strong>c</strong>hanger de
|
||||||
|
<strong>d</strong>ossier</li>
|
||||||
|
<li><code>cd ..</code> : aller dans le dossier parent</li>
|
||||||
|
<li><code>mkdir mondossier</code> : créer le dossier</li>
|
||||||
|
<li><code>python3 monfichier.py</code> : lancer le fichier Python</li>
|
||||||
|
<li><code>mv ancien nouveau</code> : déplacer ou renommer un fichier ou
|
||||||
|
dossier</li>
|
||||||
|
<li><code>cp ancien nouveau</code> : copier un fichier</li>
|
||||||
|
</ul>
|
||||||
|
<p>Raccourcis clavier :</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>CTRL+C</code> : arrêter la commande</li>
|
||||||
|
<li><code>Tab</code> : compléter automatiquement le nom de fichier</li>
|
||||||
|
<li>flèche haut/bas : historique des commandes</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="valeurs-variables-affichage">Valeurs, variables, affichage</h2>
|
||||||
|
<p>Afficher des valeurs avec <code>print</code> :</p>
|
||||||
|
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="dv">42</span>)</span>
|
||||||
|
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="dv">10</span>, <span class="dv">20</span>, <span class="dv">30</span>)</span>
|
||||||
|
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"On peut écrire du texte."</span>)</span>
|
||||||
|
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"Voici un nombre :"</span>, <span class="dv">123</span>, <span class="st">"."</span>)</span></code></pre></div>
|
||||||
|
<p>Utiliser des variables :</p>
|
||||||
|
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>annee <span class="op">=</span> <span class="dv">2025</span></span>
|
||||||
|
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"Nous sommes en"</span>, annee)</span></code></pre></div>
|
||||||
|
<p>Faire des calculs :</p>
|
||||||
|
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>annee <span class="op">=</span> <span class="dv">2025</span></span>
|
||||||
|
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>futur <span class="op">=</span> annee <span class="op">+</span> <span class="dv">10</span></span>
|
||||||
|
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"Dans 10 ans, nous serons en"</span>, futur)</span>
|
||||||
|
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>futur <span class="op">=</span> futur <span class="op">+</span> <span class="dv">5</span></span>
|
||||||
|
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"Dans 15 ans, nous serons en"</span>, futur)</span></code></pre></div>
|
||||||
|
<p>Il y a d’autres opérateurs :</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>+</code> : addition</li>
|
||||||
|
<li><code>-</code> : soustraction</li>
|
||||||
|
<li><code>*</code> : multiplication</li>
|
||||||
|
<li><code>/</code> : division</li>
|
||||||
|
<li><code>%</code> : modulo (reste de la division)</li>
|
||||||
|
<li><code>**</code> : puissance</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="faire-des-choix">Faire des choix</h2>
|
||||||
|
<p>Si (if) une valeur est vraie, alors je fais quelque chose :</p>
|
||||||
|
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="va">True</span>:</span>
|
||||||
|
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"True signifie vrai"</span>)</span>
|
||||||
|
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Donc ce code est toujours exécuté"</span>)</span>
|
||||||
|
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="va">False</span>:</span>
|
||||||
|
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"False signifie faux"</span>)</span>
|
||||||
|
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Donc ce code n'est jamais exécuté"</span>)</span>
|
||||||
|
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
|
||||||
|
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>prix <span class="op">=</span> <span class="dv">150</span></span>
|
||||||
|
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> prix <span class="op">></span> <span class="dv">100</span>:</span>
|
||||||
|
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"C'est trop cher !"</span>)</span>
|
||||||
|
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a> prix <span class="op">=</span> <span class="dv">100</span></span></code></pre></div>
|
||||||
|
<p>Il y a d’autres comparateurs :</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>==</code> : égal</li>
|
||||||
|
<li><code>!=</code> : différent</li>
|
||||||
|
<li><code><</code> : inférieur</li>
|
||||||
|
<li><code>></code> : supérieur</li>
|
||||||
|
<li><code><=</code> : inférieur ou égal</li>
|
||||||
|
<li><code>>=</code> : supérieur ou égal</li>
|
||||||
|
</ul>
|
||||||
|
<p>Sinon (else), je fais autre chose :</p>
|
||||||
|
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="dv">6</span><span class="op">*</span><span class="dv">7</span> <span class="op">==</span> <span class="dv">42</span>:</span>
|
||||||
|
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"bien !"</span>)</span>
|
||||||
|
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span>:</span>
|
||||||
|
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"oups"</span>)</span></code></pre></div>
|
||||||
|
<p>On peut aussi enchaîner plusieurs else if :</p>
|
||||||
|
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> nombre <span class="op">></span> <span class="dv">0</span>:</span>
|
||||||
|
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"le nombre est strictement positif"</span>)</span>
|
||||||
|
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="cf">elif</span> nombre <span class="op"><</span> <span class="dv">0</span>:</span>
|
||||||
|
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"le nombre est strictement négatif"</span>)</span>
|
||||||
|
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span>:</span>
|
||||||
|
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"le nombre est nul"</span>)</span></code></pre></div>
|
||||||
|
<h2 id="boucle-for">Boucle for</h2>
|
||||||
|
<p>On peut exécuter un code un nombre donné de fois :</p>
|
||||||
|
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"Je vais compter de 0 à 9 !"</span>)</span>
|
||||||
|
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">10</span>):</span>
|
||||||
|
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(i)</span>
|
||||||
|
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
|
||||||
|
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"Je vais compter de 1 à 10 !"</span>)</span>
|
||||||
|
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">1</span>, <span class="dv">11</span>):</span>
|
||||||
|
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(i)</span></code></pre></div>
|
||||||
|
<h2 id="listes">Listes</h2>
|
||||||
|
<p>Une liste est plusieurs valeurs entre crochets.</p>
|
||||||
|
<p>On peut ajouter un élément à la fin avec <code>append</code>, et
|
||||||
|
coller deux listes avec <code>+</code>.</p>
|
||||||
|
<div class="sourceCode" id="cb8"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>fruits <span class="op">=</span> []</span>
|
||||||
|
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"C'est vide :"</span>, fruits)</span>
|
||||||
|
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>fruits.append(<span class="st">"pomme"</span>)</span>
|
||||||
|
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>fruits.append(<span class="st">"kiwi"</span>)</span>
|
||||||
|
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>fruits <span class="op">=</span> fruits <span class="op">+</span> [<span class="st">"abricot"</span>, <span class="st">"orange"</span>]</span></code></pre></div>
|
||||||
|
<p>La boucle <code>for</code> exécute un code pour chaque élément de la
|
||||||
|
liste, dans l’ordre.</p>
|
||||||
|
<div class="sourceCode" id="cb9"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> fruit <span class="kw">in</span> fruits:</span>
|
||||||
|
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Ceci est un fruit :"</span>, fruit)</span></code></pre></div>
|
||||||
|
<p>On peut lire un élément donné du tableau (la numérotation commence à
|
||||||
|
0) :</p>
|
||||||
|
<div class="sourceCode" id="cb10"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="bu">file</span> <span class="op">=</span> [<span class="st">"Toto"</span>, <span class="st">"Titi"</span>, <span class="st">"Tata"</span>, <span class="st">"Tutu"</span>]</span>
|
||||||
|
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"La deuxième personne dans la file est"</span>, <span class="bu">file</span>[<span class="dv">1</span>])</span></code></pre></div>
|
||||||
|
<p>On peut changer la valeur d’un élément de la liste :</p>
|
||||||
|
<div class="sourceCode" id="cb11"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="bu">file</span>[<span class="dv">2</span>] <span class="op">=</span> <span class="st">"Anne Onyme"</span></span></code></pre></div>
|
||||||
|
<p>On peut aussi faire des listes de listes :</p>
|
||||||
|
<div class="sourceCode" id="cb12"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>stock <span class="op">=</span> [</span>
|
||||||
|
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> [<span class="st">"patates"</span>, <span class="dv">52</span>],</span>
|
||||||
|
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a> [<span class="st">"poireaux"</span>, <span class="dv">20</span>],</span>
|
||||||
|
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a> [<span class="st">"carottes"</span>, <span class="dv">40</span>]</span>
|
||||||
|
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>]</span>
|
||||||
|
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> element <span class="kw">in</span> stock:</span>
|
||||||
|
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Nombre de"</span>, element[<span class="dv">0</span>], <span class="st">":"</span>, element[<span class="dv">1</span>])</span></code></pre></div>
|
||||||
|
<p>Pour avoir à la fois l’indice (le numéro) de l’élément, et l’élément
|
||||||
|
:</p>
|
||||||
|
<div class="sourceCode" id="cb13"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>planetes <span class="op">=</span> [<span class="st">"Mercure"</span>, <span class="st">"Vénus"</span>, <span class="st">"Terre"</span>, <span class="st">"Mars"</span>]</span>
|
||||||
|
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="bu">len</span>(planetes)):</span>
|
||||||
|
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"La planète numéro"</span>, i<span class="op">+</span><span class="dv">1</span>, <span class="st">"se nomme"</span>, planetes[i])</span></code></pre></div>
|
||||||
|
<p>On peut retirer un élément avec <code>pop</code>.</p>
|
||||||
|
<div class="sourceCode" id="cb14"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>planetes <span class="op">=</span> [<span class="st">"Lune"</span>, <span class="st">"Jupiter"</span>, <span class="st">"Saturne"</span>]</span>
|
||||||
|
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="co"># Oups, la Lune n'est pas une planète.</span></span>
|
||||||
|
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"Je retire"</span>, planetes.pop(<span class="dv">0</span>), <span class="st">"de la liste."</span>)</span></code></pre></div>
|
||||||
|
<p>On peut agrandir une liste en répétant un élément un nombre donné de
|
||||||
|
fois :</p>
|
||||||
|
<div class="sourceCode" id="cb15"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>zeros <span class="op">=</span> [<span class="dv">0</span>] <span class="op">*</span> <span class="dv">1000</span></span>
|
||||||
|
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"Mille zéros !"</span>, zeros)</span></code></pre></div>
|
||||||
|
<h2 id="fonctions-mathématiques">Fonctions mathématiques</h2>
|
||||||
|
<ul>
|
||||||
|
<li><code>max(a, b)</code> : donne le plus grand nombre entre a et
|
||||||
|
b</li>
|
||||||
|
<li><code>min(a, b)</code> : donne le plus petit nombre entre a et
|
||||||
|
b</li>
|
||||||
|
<li><code>max(liste)</code> : donne la valeur maximum de la liste</li>
|
||||||
|
<li><code>min(liste)</code> : donne la valeur minimum de la liste</li>
|
||||||
|
<li><code>sum(liste)</code> : donne la somme de tous les éléments de la
|
||||||
|
liste</li>
|
||||||
|
<li><code>int(nombre)</code> : partie entière (enlève les chiffres après
|
||||||
|
la virgule)</li>
|
||||||
|
<li><code>round(nombre)</code> : arrondit au plus proche</li>
|
||||||
|
<li><code>abs(nombre)</code> : valeur absolue (distance à zéro)</li>
|
||||||
|
</ul>
|
||||||
|
<p>Pour avoir des fonctions plus avancées, il faut importer le module
|
||||||
|
<code>math</code> au début du fichier :</p>
|
||||||
|
<div class="sourceCode" id="cb16"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> math</span></code></pre></div>
|
||||||
|
<ul>
|
||||||
|
<li><code>math.pi</code> : 3.1415926…</li>
|
||||||
|
<li><code>math.sin(x)</code> : sinus</li>
|
||||||
|
<li><code>math.cos(x)</code> : cosinus</li>
|
||||||
|
<li><code>math.floor(x)</code> : arrondit à l’inférieur</li>
|
||||||
|
<li><code>math.ceil(x)</code> : arrondit au supérieur</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="aléatoire">Aléatoire</h2>
|
||||||
|
<p>Il faut importer le module <code>random</code> au début du fichier
|
||||||
|
:</p>
|
||||||
|
<div class="sourceCode" id="cb17"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> random</span></code></pre></div>
|
||||||
|
<ul>
|
||||||
|
<li><code>random.random()</code> : nombre (à virgule) aléatoire entre 0
|
||||||
|
et 1</li>
|
||||||
|
<li><code>random.randint(100, 200)</code> : nombre (entier) aléatoire
|
||||||
|
entre 100 (inclus) et 200 (inclus)</li>
|
||||||
|
<li><code>random.choice(liste)</code> : choisit un élément au hasard
|
||||||
|
dans la liste</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="fonctions-anonymes">Fonctions anonymes</h2>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
232
tuto/tutorial.md
Normal file
232
tuto/tutorial.md
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
# Tutoriel Python
|
||||||
|
|
||||||
|
## Terminal
|
||||||
|
|
||||||
|
Ouvrir un terminal : CTRL+ALT+T ou le bouton noir en bas de l'écran.
|
||||||
|
|
||||||
|
Commandes :
|
||||||
|
|
||||||
|
* `ls` : **l**i**s**ter les fichiers et dossiers
|
||||||
|
* `cd mondossier` : **c**hanger de **d**ossier
|
||||||
|
* `cd ..` : aller dans le dossier parent
|
||||||
|
* `mkdir mondossier` : créer le dossier
|
||||||
|
* `python3 monfichier.py` : lancer le fichier Python
|
||||||
|
* `mv ancien nouveau` : déplacer ou renommer un fichier ou dossier
|
||||||
|
* `cp ancien nouveau` : copier un fichier
|
||||||
|
|
||||||
|
Raccourcis clavier :
|
||||||
|
|
||||||
|
* `CTRL+C` : arrêter la commande
|
||||||
|
* `Tab` : compléter automatiquement le nom de fichier
|
||||||
|
* flèche haut/bas : historique des commandes
|
||||||
|
|
||||||
|
## Valeurs, variables, affichage
|
||||||
|
|
||||||
|
Afficher des valeurs avec `print` :
|
||||||
|
|
||||||
|
```python
|
||||||
|
print(42)
|
||||||
|
print(10, 20, 30)
|
||||||
|
print("On peut écrire du texte.")
|
||||||
|
print("Voici un nombre :", 123, ".")
|
||||||
|
```
|
||||||
|
|
||||||
|
Utiliser des variables :
|
||||||
|
|
||||||
|
```python
|
||||||
|
annee = 2025
|
||||||
|
print("Nous sommes en", annee)
|
||||||
|
```
|
||||||
|
|
||||||
|
Faire des calculs :
|
||||||
|
|
||||||
|
```python
|
||||||
|
annee = 2025
|
||||||
|
futur = annee + 10
|
||||||
|
print("Dans 10 ans, nous serons en", futur)
|
||||||
|
futur = futur + 5
|
||||||
|
print("Dans 15 ans, nous serons en", futur)
|
||||||
|
```
|
||||||
|
|
||||||
|
Il y a d'autres opérateurs :
|
||||||
|
|
||||||
|
* `+` : addition
|
||||||
|
* `-` : soustraction
|
||||||
|
* `*` : multiplication
|
||||||
|
* `/` : division
|
||||||
|
* `%` : modulo (reste de la division)
|
||||||
|
* `**` : puissance
|
||||||
|
|
||||||
|
## Faire des choix
|
||||||
|
|
||||||
|
Si (if) une valeur est vraie, alors je fais quelque chose :
|
||||||
|
|
||||||
|
```python
|
||||||
|
if True:
|
||||||
|
print("True signifie vrai")
|
||||||
|
print("Donc ce code est toujours exécuté")
|
||||||
|
if False:
|
||||||
|
print("False signifie faux")
|
||||||
|
print("Donc ce code n'est jamais exécuté")
|
||||||
|
|
||||||
|
prix = 150
|
||||||
|
if prix > 100:
|
||||||
|
print("C'est trop cher !")
|
||||||
|
prix = 100
|
||||||
|
```
|
||||||
|
|
||||||
|
Il y a d'autres comparateurs :
|
||||||
|
|
||||||
|
* `==` : égal
|
||||||
|
* `!=` : différent
|
||||||
|
* `<` : inférieur
|
||||||
|
* `>` : supérieur
|
||||||
|
* `<=` : inférieur ou égal
|
||||||
|
* `>=` : supérieur ou égal
|
||||||
|
|
||||||
|
Sinon (else), je fais autre chose :
|
||||||
|
|
||||||
|
```python
|
||||||
|
if 6*7 == 42:
|
||||||
|
print("bien !")
|
||||||
|
else:
|
||||||
|
print("oups")
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut aussi enchaîner plusieurs else if :
|
||||||
|
|
||||||
|
```python
|
||||||
|
if nombre > 0:
|
||||||
|
print("le nombre est strictement positif")
|
||||||
|
elif nombre < 0:
|
||||||
|
print("le nombre est strictement négatif")
|
||||||
|
else:
|
||||||
|
print("le nombre est nul")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Boucle for
|
||||||
|
|
||||||
|
On peut exécuter un code un nombre donné de fois :
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Je vais compter de 0 à 9 !")
|
||||||
|
for i in range(10):
|
||||||
|
print(i)
|
||||||
|
|
||||||
|
print("Je vais compter de 1 à 10 !")
|
||||||
|
for i in range(1, 11):
|
||||||
|
print(i)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Listes
|
||||||
|
|
||||||
|
Une liste est plusieurs valeurs entre crochets.
|
||||||
|
|
||||||
|
On peut ajouter un élément à la fin avec `append`, et coller deux listes avec `+`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
fruits = []
|
||||||
|
print("C'est vide :", fruits)
|
||||||
|
fruits.append("pomme")
|
||||||
|
fruits.append("kiwi")
|
||||||
|
fruits = fruits + ["abricot", "orange"]
|
||||||
|
```
|
||||||
|
|
||||||
|
La boucle `for` exécute un code pour chaque élément de la liste, dans l'ordre.
|
||||||
|
|
||||||
|
```python
|
||||||
|
for fruit in fruits:
|
||||||
|
print("Ceci est un fruit :", fruit)
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut lire un élément donné du tableau (la numérotation commence à 0) :
|
||||||
|
|
||||||
|
```python
|
||||||
|
file = ["Toto", "Titi", "Tata", "Tutu"]
|
||||||
|
print("La deuxième personne dans la file est", file[1])
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut changer la valeur d'un élément de la liste :
|
||||||
|
|
||||||
|
```python
|
||||||
|
file[2] = "Anne Onyme"
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut aussi faire des listes de listes :
|
||||||
|
|
||||||
|
```python
|
||||||
|
stock = [
|
||||||
|
["patates", 52],
|
||||||
|
["poireaux", 20],
|
||||||
|
["carottes", 40]
|
||||||
|
]
|
||||||
|
for element in stock:
|
||||||
|
print("Nombre de", element[0], ":", element[1])
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour avoir à la fois l'indice (le numéro) de l'élément, et l'élément :
|
||||||
|
|
||||||
|
```python
|
||||||
|
planetes = ["Mercure", "Vénus", "Terre", "Mars"]
|
||||||
|
for i in range(len(planetes)):
|
||||||
|
print("La planète numéro", i+1, "se nomme", planetes[i])
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut retirer un élément avec `pop`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
planetes = ["Lune", "Jupiter", "Saturne"]
|
||||||
|
# Oups, la Lune n'est pas une planète.
|
||||||
|
print("Je retire", planetes.pop(0), "de la liste.")
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut agrandir une liste en répétant un élément un nombre donné de fois :
|
||||||
|
|
||||||
|
```python
|
||||||
|
zeros = [0] * 1000
|
||||||
|
print("Mille zéros !", zeros)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fonctions mathématiques
|
||||||
|
|
||||||
|
* `max(a, b)` : donne le plus grand nombre entre a et b
|
||||||
|
* `min(a, b)` : donne le plus petit nombre entre a et b
|
||||||
|
* `max(liste)` : donne la valeur maximum de la liste
|
||||||
|
* `min(liste)` : donne la valeur minimum de la liste
|
||||||
|
* `sum(liste)` : donne la somme de tous les éléments de la liste
|
||||||
|
* `int(nombre)` : partie entière (enlève les chiffres après la virgule)
|
||||||
|
* `round(nombre)` : arrondit au plus proche
|
||||||
|
* `abs(nombre)` : valeur absolue (distance à zéro)
|
||||||
|
|
||||||
|
Pour avoir des fonctions plus avancées, il faut importer le module `math` au début du fichier :
|
||||||
|
|
||||||
|
```python
|
||||||
|
import math
|
||||||
|
```
|
||||||
|
|
||||||
|
* `math.pi` : 3.1415926...
|
||||||
|
* `math.sin(x)` : sinus
|
||||||
|
* `math.cos(x)` : cosinus
|
||||||
|
* `math.floor(x)` : arrondit à l'inférieur
|
||||||
|
* `math.ceil(x)` : arrondit au supérieur
|
||||||
|
|
||||||
|
## Aléatoire
|
||||||
|
|
||||||
|
Il faut importer le module `random` au début du fichier :
|
||||||
|
|
||||||
|
```python
|
||||||
|
import random
|
||||||
|
```
|
||||||
|
|
||||||
|
* `random.random()` : nombre (à virgule) aléatoire entre 0 et 1
|
||||||
|
* `random.randint(100, 200)` : nombre (entier) aléatoire entre 100 (inclus) et 200 (inclus)
|
||||||
|
* `random.choice(liste)` : choisit un élément au hasard dans la liste
|
||||||
|
|
||||||
|
## Fonctions anonymes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BIN
tuto/tutorial.pdf
Normal file
BIN
tuto/tutorial.pdf
Normal file
Binary file not shown.
BIN
zelda.mid
Normal file
BIN
zelda.mid
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue