2
# -*- coding: utf-8 -*-
4
# pySFML - Python bindings for SFML
5
# Copyright 2012-2013, Jonathan De Wachter <dewachter.jonathan@gmail.com>
7
# This software is released under the LGPLv3 license.
8
# You should have received a copy of the GNU Lesser General Public License
9
# along with this program. If not, see <http://www.gnu.org/licenses/>.
11
#from libc.stdlib cimport malloc, free
12
#from cython.operator cimport preincrement as preinc, dereference as deref
15
from libc.stdlib cimport malloc, free
16
from libc.string cimport memcpy
18
cimport libcpp.sfml as sf
19
from libcpp.sfml cimport Int8, Int16, Int32, Int64
20
from libcpp.sfml cimport Uint8, Uint16, Uint32, Uint64
21
from libcpp.sfml cimport Vector3f
24
cdef extern from "pysfml/system_api.h":
25
object popLastErrorMessage()
26
int import_sfml__system()
29
cdef extern from "DerivableSoundStream.hpp":
30
cdef cppclass DerivableSoundStream:
31
DerivableSoundStream(void*)
32
void initialize(unsigned int, unsigned int)
34
cdef extern from "DerivableSoundRecorder.hpp":
35
cdef cppclass DerivableSoundRecorder:
36
DerivableSoundRecorder(void*)
38
from pysfml.system cimport Vector3, Time
39
from pysfml.system cimport to_vector3
41
cdef Time wrap_time(sf.Time* p):
42
cdef Time r = Time.__new__(Time)
49
NotImplementedError("This class is not meant to be instanciated!")
52
def get_global_volume(cls):
53
return sf.listener.getGlobalVolume()
56
def set_global_volume(cls, float volume):
57
sf.listener.setGlobalVolume(volume)
60
def get_position(cls):
61
cdef Vector3f v = sf.listener.getPosition()
65
def set_position(cls, position):
67
sf.listener.setPosition(x, y, z)
70
def get_direction(cls):
71
cdef Vector3f v = sf.listener.getDirection()
75
def set_direction(cls, direction):
77
sf.listener.setDirection(x, y, z)
81
cdef size_t m_sampleCount
86
self.m_sampleCount = 0
87
self.delete_this = False
89
def __dealloc__(self):
94
return self.m_sampleCount
96
def __getitem__(self, size_t key):
97
return self.m_samples[key]
99
def __setitem__(self, size_t key, Int16 other):
100
self.m_samples[key] = other
104
return (<char*>self.m_samples)[:len(self)*2]
106
def __set__(self, bdata):
107
cdef char* data = <bytes>bdata
110
raise ValueError("Chunk data lenght must be even as it represents a 16bit array")
114
self.m_sampleCount = 0
116
self.m_samples = <Int16*>malloc(len(bdata))
117
memcpy(self.m_samples, data, len(bdata))
118
self.m_sampleCount = len(bdata) // 2
120
self.delete_this = True
122
cdef api object create_chunk():
123
cdef Chunk r = Chunk.__new__(Chunk)
126
r.delete_this = False
129
cdef api Int16* terminate_chunk(chunk):
130
cdef Chunk p = <Chunk>chunk
131
p.delete_this = False
134
cdef api object wrap_chunk(Int16* samples, unsigned int sample_count, bint delete):
135
cdef Chunk r = Chunk.__new__(Chunk)
136
r.m_samples = samples
137
r.m_sampleCount = sample_count
138
r.delete_this = delete
141
cdef class SoundBuffer:
142
cdef sf.SoundBuffer *p_this
143
cdef bint delete_this
146
raise UserWarning("Use specific methods")
148
def __dealloc__(self):
149
if self.delete_this: del self.p_this
151
def __repr__(self): pass
152
def __str__(self): pass
155
def from_file(cls, filename):
156
cdef sf.SoundBuffer *p = new sf.SoundBuffer()
157
cdef char* encoded_filename
159
encoded_filename_temporary = filename.encode('UTF-8')
160
encoded_filename = encoded_filename_temporary
162
if p.loadFromFile(encoded_filename): return wrap_soundbuffer(p)
165
raise IOError(popLastErrorMessage())
168
def from_memory(cls, bytes data):
169
cdef sf.SoundBuffer *p = new sf.SoundBuffer()
171
if p.loadFromMemory(<char*>data, len(data)): return wrap_soundbuffer(p)
174
raise IOError(popLastErrorMessage())
177
def from_samples(cls, Chunk samples, unsigned int channel_count, unsigned int sample_rate):
178
cdef sf.SoundBuffer *p = new sf.SoundBuffer()
180
if p.loadFromSamples(samples.m_samples, samples.m_sampleCount, channel_count, sample_rate):
181
return wrap_soundbuffer(p)
184
raise IOError(popLastErrorMessage())
186
def to_file(self, filename):
187
cdef char* encoded_filename
189
encoded_filename_temporary = filename.encode('UTF-8')
190
encoded_filename = encoded_filename_temporary
192
self.p_this.saveToFile(encoded_filename)
196
cdef Chunk r = Chunk.__new__(Chunk)
197
r.m_samples = <Int16*>self.p_this.getSamples()
198
r.m_sampleCount = self.p_this.getSampleCount()
201
property sample_rate:
203
return self.p_this.getSampleRate()
205
property channel_count:
207
return self.p_this.getChannelCount()
211
cdef sf.Time* p = new sf.Time()
212
p[0] = self.p_this.getDuration()
215
cdef SoundBuffer wrap_soundbuffer(sf.SoundBuffer *p, bint delete_this=True):
216
cdef SoundBuffer r = SoundBuffer.__new__(SoundBuffer)
218
r.delete_this = delete_this
222
cdef class SoundSource:
223
STOPPED = sf.soundsource.Stopped
224
PAUSED = sf.soundsource.Paused
225
PLAYING = sf.soundsource.Playing
227
cdef sf.SoundSource *p_soundsource
229
def __init__(self, *args, **kwargs):
230
raise UserWarning("This class is not meant to be used directly")
234
return self.p_soundsource.getPitch()
236
def __set__(self, float pitch):
237
self.p_soundsource.setPitch(pitch)
241
return self.p_soundsource.getVolume()
243
def __set__(self, float volume):
244
self.p_soundsource.setVolume(volume)
248
cdef Vector3f v = self.p_soundsource.getPosition()
249
return to_vector3(&v)
251
def __set__(self, position):
253
self.p_soundsource.setPosition(x, y, z)
255
property relative_to_listener:
257
return self.p_soundsource.isRelativeToListener()
259
def __set__(self, bint relative):
260
self.p_soundsource.setRelativeToListener(relative)
262
property min_distance:
264
return self.p_soundsource.getMinDistance()
266
def __set__(self, float distance):
267
self.p_soundsource.setMinDistance(distance)
269
property attenuation:
271
return self.p_soundsource.getAttenuation()
273
def __set__(self, float attenuation):
274
self.p_soundsource.setAttenuation(attenuation)
277
cdef class Sound(SoundSource):
278
cdef sf.Sound *p_this
279
cdef SoundBuffer m_buffer
281
def __init__(self, SoundBuffer buffer=None):
282
self.p_this = new sf.Sound()
283
self.p_soundsource = <sf.SoundSource*>self.p_this
285
if buffer: self.buffer = buffer
287
def __dealloc__(self):
306
def __set__(self, SoundBuffer buffer):
307
self.p_this.setBuffer(buffer.p_this[0])
308
self.m_buffer = buffer
312
return self.p_this.getLoop()
314
def __set__(self, bint loop):
315
self.p_this.setLoop(loop)
317
property playing_offset:
319
cdef sf.Time* p = new sf.Time()
320
p[0] = self.p_this.getPlayingOffset()
323
def __set__(self, Time time_offset):
324
self.p_this.setPlayingOffset(time_offset.p_this[0])
328
return self.p_this.getStatus()
331
cdef class SoundStream(SoundSource):
332
cdef sf.SoundStream *p_soundstream
335
if self.__class__ == SoundStream:
336
raise NotImplementedError("SoundStream is abstract")
338
elif self.__class__ not in [Music]:
339
self.p_soundstream = <sf.SoundStream*> new DerivableSoundStream(<void*>self)
340
self.p_soundsource = <sf.SoundSource*>self.p_soundstream
343
self.p_soundstream.play()
346
self.p_soundstream.pause()
349
self.p_soundstream.stop()
351
property channel_count:
353
return self.p_soundstream.getChannelCount()
355
property sample_rate:
357
return self.p_soundstream.getSampleRate()
361
return self.p_soundstream.getStatus()
363
property playing_offset:
365
cdef sf.Time* p = new sf.Time()
366
p[0] = self.p_soundstream.getPlayingOffset()
369
def __set__(self, Time time_offset):
370
self.p_soundstream.setPlayingOffset(time_offset.p_this[0])
374
return self.p_soundstream.getLoop()
376
def __set__(self, bint loop):
377
self.p_soundstream.setLoop(loop)
379
def initialize(self, unsigned int channel_count, unsigned int sample_rate):
380
if self.__class__ not in [Music]:
381
(<DerivableSoundStream*>self.p_soundstream).initialize(channel_count, sample_rate)
383
def on_get_data(self, data): pass
384
def on_seek(self, time_offset): pass
386
cdef class Music(SoundStream):
387
cdef sf.Music *p_this
390
raise UserWarning("Use specific constructor")
392
def __dealloc__(self):
396
def from_file(cls, filename):
397
cdef sf.Music *p = new sf.Music()
398
cdef char* encoded_filename
400
encoded_filename_temporary = filename.encode('UTF-8')
401
encoded_filename = encoded_filename_temporary
403
if p.openFromFile(encoded_filename): return wrap_music(p)
406
raise IOError(popLastErrorMessage())
409
def from_memory(cls, bytes data):
410
cdef sf.Music *p = new sf.Music()
412
if p.openFromMemory(<char*>data, len(data)): return wrap_music(p)
415
raise IOError(popLastErrorMessage())
419
cdef sf.Time* p = new sf.Time()
420
p[0] = self.p_this.getDuration()
424
cdef Music wrap_music(sf.Music *p):
425
cdef Music r = Music.__new__(Music)
427
r.p_soundstream = <sf.SoundStream*>p
428
r.p_soundsource = <sf.SoundSource*>p
432
cdef class SoundRecorder:
433
cdef sf.SoundRecorder *p_soundrecorder
436
if self.__class__ == SoundRecorder:
437
raise NotImplementedError("SoundRecorder is abstract")
439
elif self.__class__ is not SoundBufferRecorder:
440
self.p_soundrecorder = <sf.SoundRecorder*>new DerivableSoundRecorder(<void*>self)
442
def __dealloc__(self):
443
if self.__class__ is SoundRecorder:
444
del self.p_soundrecorder
446
def start(self, unsigned int sample_rate=44100):
447
self.p_soundrecorder.start(sample_rate)
450
with nogil: self.p_soundrecorder.stop()
452
property sample_rate:
454
return self.p_soundrecorder.getSampleRate()
457
def is_available(cls):
458
return sf.soundrecorder.isAvailable()
463
def on_process_samples(self, chunk):
469
cdef class SoundBufferRecorder(SoundRecorder):
470
cdef sf.SoundBufferRecorder *p_this
471
cdef SoundBuffer m_buffer
474
self.p_this = new sf.SoundBufferRecorder()
475
self.p_soundrecorder = <sf.SoundRecorder*>self.p_this
477
self.m_buffer = wrap_soundbuffer(<sf.SoundBuffer*>&self.p_this.getBuffer(), False)
479
def __dealloc__(self):