1 2from __future__ import with_statement 3 4import threading 5import logging 6import time 7from ctypes import * 8from JetUtils import OsWindows 9 10 11# stream state 12EAS_STATE_READY = 0 13EAS_STATE_PLAY = 1 14EAS_STATE_STOPPING = 2 15EAS_STATE_PAUSING = 3 16EAS_STATE_STOPPED = 4 17EAS_STATE_PAUSED = 5 18EAS_STATE_OPEN = 6 19EAS_STATE_ERROR = 7 20EAS_STATE_EMPTY = 8 21 22# EAS error codes 23EAS_SUCCESS = 0 24EAS_FAILURE = -1 25EAS_ERROR_INVALID_MODULE = -2 26EAS_ERROR_MALLOC_FAILED = -3 27EAS_ERROR_FILE_POS = -4 28EAS_ERROR_INVALID_FILE_MODE = -5 29EAS_ERROR_FILE_SEEK = -6 30EAS_ERROR_FILE_LENGTH = -7 31EAS_ERROR_NOT_IMPLEMENTED = -8 32EAS_ERROR_CLOSE_FAILED = -9 33EAS_ERROR_FILE_OPEN_FAILED = -10 34EAS_ERROR_INVALID_HANDLE = -11 35EAS_ERROR_NO_MIX_BUFFER = -12 36EAS_ERROR_PARAMETER_RANGE = -13 37EAS_ERROR_MAX_FILES_OPEN = -14 38EAS_ERROR_UNRECOGNIZED_FORMAT = -15 39EAS_BUFFER_SIZE_MISMATCH = -16 40EAS_ERROR_FILE_FORMAT = -17 41EAS_ERROR_SMF_NOT_INITIALIZED = -18 42EAS_ERROR_LOCATE_BEYOND_END = -19 43EAS_ERROR_INVALID_PCM_TYPE = -20 44EAS_ERROR_MAX_PCM_STREAMS = -21 45EAS_ERROR_NO_VOICE_ALLOCATED = -22 46EAS_ERROR_INVALID_CHANNEL = -23 47EAS_ERROR_ALREADY_STOPPED = -24 48EAS_ERROR_FILE_READ_FAILED = -25 49EAS_ERROR_HANDLE_INTEGRITY = -26 50EAS_ERROR_MAX_STREAMS_OPEN = -27 51EAS_ERROR_INVALID_PARAMETER = -28 52EAS_ERROR_FEATURE_NOT_AVAILABLE = -29 53EAS_ERROR_SOUND_LIBRARY = -30 54EAS_ERROR_NOT_VALID_IN_THIS_STATE = -31 55EAS_ERROR_NO_VIRTUAL_SYNTHESIZER = -32 56EAS_ERROR_FILE_ALREADY_OPEN = -33 57EAS_ERROR_FILE_ALREADY_CLOSED = -34 58EAS_ERROR_INCOMPATIBLE_VERSION = -35 59EAS_ERROR_QUEUE_IS_FULL = -36 60EAS_ERROR_QUEUE_IS_EMPTY = -37 61EAS_ERROR_FEATURE_ALREADY_ACTIVE = -38 62 63# special result codes 64EAS_EOF = 3 65EAS_STREAM_BUFFERING = 4 66 67# buffer full error returned from Render 68EAS_BUFFER_FULL = 5 69 70# file types 71file_types = ( 72 'Unknown', 73 'SMF Type 0 (.mid)', 74 'SMF Type 1 (.mid)', 75 'SMAF - Unknown type (.mmf)', 76 'SMAF MA-2 (.mmf)', 77 'SMAF MA-3 (.mmf)', 78 'SMAF MA-5 (.mmf)', 79 'CMX/QualComm (.pmd)', 80 'MFi (NTT/DoCoMo i-mode)', 81 'OTA/Nokia (.ott)', 82 'iMelody (.imy)', 83 'RTX/RTTTL (.rtx)', 84 'XMF Type 0 (.xmf)', 85 'XMF Type 1 (.xmf)', 86 'WAVE/PCM (.wav)', 87 'WAVE/IMA-ADPCM (.wav)', 88 'MMAPI Tone Control (.js)' 89) 90 91stream_states = ( 92 'Ready', 93 'Play', 94 'Stopping', 95 'Stopped', 96 'Pausing', 97 'Paused', 98 'Open', 99 'Error', 100 'Empty' 101) 102 103# iMode play modes 104IMODE_PLAY_ALL = 0 105IMODE_PLAY_PARTIAL = 1 106 107# callback type for metadata 108EAS_METADATA_CBFUNC = CFUNCTYPE(c_int, c_int, c_char_p, c_ulong) 109 110# callbacks for external audio 111EAS_EXT_PRG_CHG_FUNC = CFUNCTYPE(c_int, c_void_p, c_void_p) 112EAS_EXT_EVENT_FUNC = CFUNCTYPE(c_int, c_void_p, c_void_p) 113 114# callback for aux mixer decoder 115EAS_DECODER_FUNC = CFUNCTYPE(c_void_p, c_void_p, c_int, c_int) 116 117# DLL path 118if OsWindows(): 119 EAS_DLL_PATH = "EASDLL.dll" 120else: 121 EAS_DLL_PATH = "libEASLIb.dylib" 122 123eas_dll = None 124 125# logger 126eas_logger = None 127 128#--------------------------------------------------------------- 129# InitEASModule 130#--------------------------------------------------------------- 131def InitEASModule (dll_path=None): 132 global eas_dll 133 global eas_logger 134 135 136 # initialize logger 137 if eas_logger is None: 138 eas_logger = logging.getLogger('EAS') 139 140 # initialize path to DLL 141 if dll_path is None: 142 dll_path=EAS_DLL_PATH 143 144 # intialize DLL 145 if eas_dll is None: 146 eas_dll = cdll.LoadLibrary(dll_path) 147 148#--------------------------------------------------------------- 149# S_JET_CONFIG 150#--------------------------------------------------------------- 151class S_JET_CONFIG (Structure): 152 _fields_ = [('appLowNote', c_ubyte)] 153 154#--------------------------------------------------------------- 155# S_EXT_AUDIO_PRG_CHG 156#--------------------------------------------------------------- 157class S_EXT_AUDIO_PRG_CHG (Structure): 158 _fields_ = [('bank', c_ushort), 159 ('program', c_ubyte), 160 ('channel', c_ubyte)] 161 162#--------------------------------------------------------------- 163# S_EXT_AUDIO_EVENT 164#--------------------------------------------------------------- 165class S_EXT_AUDIO_EVENT (Structure): 166 _fields_ = [('channel', c_ubyte), 167 ('note', c_ubyte), 168 ('velocity', c_ubyte), 169 ('noteOn', c_ubyte)] 170 171#--------------------------------------------------------------- 172# S_MIDI_CONTROLLERS 173#--------------------------------------------------------------- 174class S_MIDI_CONTROLLERS (Structure): 175 _fields_ = [('modWheel', c_ubyte), 176 ('volume', c_ubyte), 177 ('pan', c_ubyte), 178 ('expression', c_ubyte), 179 ('channelPressure', c_ubyte)] 180 181#--------------------------------------------------------------- 182# WAVEFORMAT 183#--------------------------------------------------------------- 184class WAVEFORMAT (Structure): 185 _fields_ = [('wFormatTag', c_ushort), 186 ('nChannels', c_ushort), 187 ('nSamplesPerSec', c_ulong), 188 ('nAvgBytesPerSec', c_ulong), 189 ('nBlockAlign', c_ushort), 190 ('wBitsPerSample', c_ushort)] 191 192#--------------------------------------------------------------- 193# EAS_Exception 194#--------------------------------------------------------------- 195class EAS_Exception (Exception): 196 def __init__ (self, result_code, msg, function=None): 197 self.msg = msg 198 self.result_code = result_code 199 self.function = function 200 def __str__ (self): 201 return self.msg 202 203#--------------------------------------------------------------- 204# Log callback function 205#--------------------------------------------------------------- 206# map EAS severity levels to the Python logging module 207severity_mapping = (logging.CRITICAL, logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG) 208LOG_FUNC_TYPE = CFUNCTYPE(c_int, c_int, c_char_p) 209def Log (level, msg): 210 eas_logger.log(severity_mapping[level], msg) 211 return level 212LogCallback = LOG_FUNC_TYPE(Log) 213 214#--------------------------------------------------------------- 215# EAS_Stream 216#--------------------------------------------------------------- 217class EAS_Stream (object): 218 def __init__ (self, handle, eas): 219 eas_logger.debug('EAS_Stream.__init__') 220 self.handle = handle 221 self.eas = eas 222 223 def SetVolume (self, volume): 224 """Set the stream volume""" 225 eas_logger.debug('Call EAS_SetVolume: volume=%d' % volume) 226 with self.eas.lock: 227 result = eas_dll.EAS_SetVolume(self.eas.handle, self.handle, volume) 228 if result: 229 raise EAS_Exception(result, 'EAS_SetVolume error %d on file %s' % (result, self.path), 'EAS_SetVolume') 230 231 def GetVolume (self): 232 """Get the stream volume.""" 233 eas_logger.debug('Call EAS_GetVolume') 234 with self.eas.lock: 235 volume = eas_dll.EAS_GetVolume(self.eas.handle, self.handle) 236 if volume < 0: 237 raise EAS_Exception(volume, 'EAS_GetVolume error %d on file %s' % (volume, self.path), 'EAS_GetVolume') 238 eas_logger.debug('EAS_GetVolume: volume=%d' % volume) 239 return volume 240 241 def SetPriority (self, priority): 242 """Set the stream priority""" 243 eas_logger.debug('Call EAS_SetPriority: priority=%d' % priority) 244 with self.eas.lock: 245 result = eas_dll.EAS_SetPriority(self.eas.handle, self.handle, priority) 246 if result: 247 raise EAS_Exception(result, 'EAS_SetPriority error %d on file %s' % (result, self.path), 'EAS_SetPriority') 248 249 def GetPriority (self): 250 """Get the stream priority.""" 251 eas_logger.debug('Call EAS_GetPriority') 252 priority = c_int(0) 253 with self.eas.lock: 254 result = eas_dll.EAS_GetPriority(self.eas.handle, self.handle, byref(priority)) 255 if result: 256 raise EAS_Exception(result, 'EAS_GetPriority error %d on file %s' % (result, self.path), 'EAS_GetPriority') 257 eas_logger.debug('EAS_GetPriority: priority=%d' % priority.value) 258 return priority.value 259 260 def SetTransposition (self, transposition): 261 """Set the transposition of a stream.""" 262 eas_logger.debug('Call EAS_SetTransposition: transposition=%d' % transposition) 263 with self.eas.lock: 264 result = eas_dll.EAS_SetTransposition(self.eas.handle, self.handle, transposition) 265 if result: 266 raise EAS_Exception(result, 'EAS_SetTransposition error %d on file %s' % (result, self.path), 'EAS_SetTransposition') 267 268 def SetPolyphony (self, polyphony): 269 """Set the polyphony of a stream.""" 270 eas_logger.debug('Call EAS_SetPolyphony: polyphony=%d' % polyphony) 271 with self.eas.lock: 272 result = eas_dll.EAS_SetPolyphony(self.eas.handle, self.handle, polyphony) 273 if result: 274 raise EAS_Exception(result, 'EAS_SetPolyphony error %d on file %s' % (result, self.path), 'EAS_SetPolyphony') 275 276 def GetPolyphony (self): 277 """Get the polyphony of a stream.""" 278 eas_logger.debug('Call EAS_GetPolyphony') 279 polyphony = c_int(0) 280 with self.eas.lock: 281 result = eas_dll.EAS_GetPolyphony(self.eas.handle, self.handle, byref(polyphony)) 282 if result: 283 raise EAS_Exception(result, 'EAS_GetPolyphony error %d on file %s' % (result, self.path), 'EAS_GetPolyphony') 284 eas_logger.debug('EAS_SetPolyphony: polyphony=%d' % polyphony.value) 285 return polyphony.value 286 287 def SelectLib (self, test_lib=False): 288 eas_logger.debug('Call EAS_SelectLib: test_lib=%s' % test_lib) 289 with self.eas.lock: 290 result = eas_dll.EAS_SelectLib(self.eas.handle, self.handle, test_lib) 291 if result: 292 raise EAS_Exception(result, 'EAS_SelectLib error %d on file %s' % (result, self.path), 'EAS_SelectLib') 293 294 def LoadDLSCollection (self, path): 295 eas_logger.debug('Call EAS_LoadDLSCollection: lib_path=%d' % path) 296 with self.eas.lock: 297 result = eas_dll.EAS_LoadDLSCollection(self.eas.handle, self.handle, path) 298 if result: 299 raise EAS_Exception(result, 'EAS_LoadDLSCollection error %d on file %s lib %s' % (result, self.path, path), 'EAS_LoadDLSCollection') 300 301 def RegExtAudioCallback (self, user_data, prog_chg_func, event_func): 302 """Register an external audio callback.""" 303 eas_logger.debug('Call EAS_RegExtAudioCallback') 304 if prog_chg_func is not None: 305 prog_chg_func = EAS_EXT_PRG_CHG_FUNC(prog_chg_func) 306 else: 307 prog_chg_func = 0 308 if event_func is not None: 309 event_func = EAS_EXT_EVENT_FUNC(event_func) 310 else: 311 event_func = 0 312 with self.eas.lock: 313 result = eas_dll.EAS_RegExtAudioCallback(self.eas.handle, self.handle, user_data, prog_chg_func, event_func) 314 if result: 315 raise EAS_Exception(result, 'EAS_RegExtAudioCallback error %d on file %s' % (result, self.path), 'EAS_RegExtAudioCallback') 316 317 def SetPlayMode (self, play_mode): 318 """Set play mode on a stream.""" 319 eas_logger.debug('Call EAS_SetPlayMode: play_mode=%d' % play_mode) 320 with self.eas.lock: 321 result = eas_dll.EAS_SetPlayMode(self.eas.handle, self.handle, play_mode) 322 if result: 323 raise EAS_Exception(result, 'EAS_SetPlayMode error %d on file %s' % (result, self.path), 'EAS_SetPlayMode') 324 325""" 326EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE streamHandle, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl); 327""" 328 329#--------------------------------------------------------------- 330# EAS_File 331#--------------------------------------------------------------- 332class EAS_File (EAS_Stream): 333 def __init__ (self, path, handle, eas): 334 EAS_Stream.__init__(self, handle, eas) 335 eas_logger.debug('EAS_File.__init__') 336 self.path = path 337 self.prepared = False 338 339 def Prepare (self): 340 """Prepare an audio file for playback""" 341 if self.prepared: 342 eas_logger.warning('Prepare already called on file %s' % self.path) 343 else: 344 with self.eas.lock: 345 eas_logger.debug('Call EAS_Prepare for file: %s' % self.path) 346 result = eas_dll.EAS_Prepare(self.eas.handle, self.handle) 347 if result: 348 raise EAS_Exception(result, 'EAS_Prepare error %d on file %s' % (result, self.path), 'EAS_Prepare') 349 self.prepared = True 350 351 def State (self): 352 """Get stream state.""" 353 with self.eas.lock: 354 eas_logger.debug('Call EAS_State for file: %s' % self.path) 355 state = c_long(-1) 356 result = eas_dll.EAS_State(self.eas.handle, self.handle, byref(state)) 357 if result: 358 raise EAS_Exception(result, 'EAS_State error %d on file %s' % (result, self.path), 'EAS_State') 359 eas_logger.debug('EAS_State: file=%s, state=%s' % (self.path, stream_states[state.value])) 360 return state.value 361 362 def Close (self): 363 """Close audio file.""" 364 if hasattr(self, 'handle'): 365 with self.eas.lock: 366 eas_logger.debug('Call EAS_CloseFile for file: %s' % self.path) 367 result = eas_dll.EAS_CloseFile(self.eas.handle, self.handle) 368 if result: 369 raise EAS_Exception(result, 'EAS_CloseFile error %d on file %s' % (result, self.path), 'EAS_CloseFile') 370 371 # remove file from the EAS object 372 self.eas.audio_streams.remove(self) 373 374 # clean up references 375 del self.handle 376 del self.eas 377 del self.path 378 379 def Pause (self): 380 """Pause a stream.""" 381 eas_logger.debug('Call EAS_Pause') 382 with self.eas.lock: 383 result = eas_dll.EAS_Pause(self.eas.handle, self.handle) 384 if result: 385 raise EAS_Exception(result, 'EAS_Pause error %d on file %s' % (result, self.path), 'EAS_Pause') 386 387 def Resume (self): 388 """Resume a stream.""" 389 eas_logger.debug('Call EAS_Resume') 390 with self.eas.lock: 391 result = eas_dll.EAS_Resume(self.eas.handle, self.handle) 392 if result: 393 raise EAS_Exception(result, 'EAS_Resume error %d on file %s' % (result, self.path), 'EAS_Resume') 394 395 def Locate (self, secs, offset=False): 396 """Set the playback position of a stream in seconds.""" 397 eas_logger.debug('Call EAS_Locate: location=%.3f, relative=%s' % (secs, offset)) 398 with self.eas.lock: 399 result = eas_dll.EAS_Locate(self.eas.handle, self.handle, int(secs * 1000 + 0.5), offset) 400 if result: 401 raise EAS_Exception(result, 'EAS_Locate error %d on file %s' % (result, self.path), 'EAS_Locate') 402 403 def GetLocation (self): 404 """Get the stream location in seconds.""" 405 eas_logger.debug('Call EAS_GetLocation') 406 msecs = c_int(0) 407 with self.eas.lock: 408 result = eas_dll.EAS_GetLocation(self.eas.handle, self.handle, byref(msecs)) 409 if result: 410 raise EAS_Exception(result, 'EAS_GetLocation error %d on file %s' % (result, self.path), 'EAS_GetLocation') 411 msecs = float(msecs.value) / 1000 412 eas_logger.debug('EAS_GetLocation: location=%.3f' % msecs) 413 return msecs 414 415 def GetFileType (self): 416 """Get the file type.""" 417 eas_logger.debug('Call EAS_GetFileType') 418 file_type = c_int(0) 419 with self.eas.lock: 420 result = eas_dll.EAS_GetFileType(self.eas.handle, self.handle, byref(file_type)) 421 if result: 422 raise EAS_Exception(result, 'EAS_GetFileType error %d on file %s' % (result, self.path), 'EAS_GetFileType') 423 file_type = file_type.value 424 if file_type < len(file_types): 425 file_desc = file_types[file_type] 426 else: 427 file_desc = 'Unrecognized type %d' % file_type 428 eas_logger.debug('EAS_GetFileType: type=%d, desc=%s' % (file_type, file_desc)) 429 return (file_type, file_desc) 430 431 def SetRepeat (self, count): 432 """Set the repeat count of a stream.""" 433 eas_logger.debug('Call EAS_SetRepeat: count=%d' % count) 434 with self.eas.lock: 435 result = eas_dll.EAS_SetRepeat(self.eas.handle, self.handle, count) 436 if result: 437 raise EAS_Exception(result, 'EAS_SetRepeat error %d on file %s' % (result, self.path), 'EAS_SetRepeat') 438 439 def GetRepeat (self): 440 """Get the repeat count of a stream.""" 441 eas_logger.debug('Call EAS_GetRepeat') 442 count = c_int(0) 443 with self.eas.lock: 444 result = eas_dll.EAS_GetRepeat(self.eas.handle, self.handle, byref(count)) 445 if result: 446 raise EAS_Exception(result, 'EAS_GetRepeat error %d on file %s' % (result, self.path), 'EAS_GetRepeat') 447 eas_logger.debug('EAS_GetRepeat: count=%d' % count.value) 448 return count.value 449 450 def SetPlaybackRate (self, rate): 451 """Set the playback rate of a stream.""" 452 eas_logger.debug('Call EAS_SetPlaybackRate') 453 with self.eas.lock: 454 result = eas_dll.EAS_SetPlaybackRate(self.eas.handle, self.handle, rate) 455 if result: 456 raise EAS_Exception(result, 'EAS_SetPlaybackRate error %d on file %s' % (result, self.path), 'EAS_SetPlaybackRate') 457 458 def ParseMetaData (self): 459 """Parse the metadata in a file.""" 460 eas_logger.debug('Call EAS_ParseMetaData') 461 length = c_int(0) 462 with self.eas.lock: 463 result = eas_dll.EAS_ParseMetaData(self.eas.handle, self.handle, byref(length)) 464 if result: 465 raise EAS_Exception(result, 'EAS_ParseMetaData error %d on file %s' % (result, self.path), 'EAS_ParseMetaData') 466 return float(length.value) / 1000.0 467 468 def RegisterMetaDataCallback (self, func, buf, buf_size, user_data): 469 """Register a metadata callback.""" 470 eas_logger.debug('Call EAS_RegisterMetaDataCallback') 471 with self.eas.lock: 472 if func is not None: 473 callback = EAS_METADATA_CBFUNC(func) 474 else: 475 callback = 0 476 result = eas_dll.EAS_RegisterMetaDataCallback(self.eas.handle, self.handle, callback, buf, buf_size, user_data) 477 if result: 478 raise EAS_Exception(result, 'EAS_RegisterMetaDataCallback error %d on file %s' % (result, self.path), 'EAS_RegisterMetaDataCallback') 479 480 def GetWaveFmtChunk (self): 481 """Get the file type.""" 482 eas_logger.debug('Call EAS_GetWaveFmtChunk') 483 wave_fmt_chunk = c_void_p(0) 484 with self.eas.lock: 485 result = eas_dll.EAS_GetWaveFmtChunk(self.eas.handle, self.handle, byref(wave_fmt_chunk)) 486 if result: 487 raise EAS_Exception(result, 'EAS_GetWaveFmtChunk error %d on file %s' % (result, self.path), 'EAS_GetWaveFmtChunk') 488 return cast(wave_fmt_chunk, POINTER(WAVEFORMAT)).contents 489 490 def Play (self, max_time=None): 491 """Plays the file to the end or max_time.""" 492 eas_logger.debug('EAS_File.Play') 493 if not self.prepared: 494 self.Prepare() 495 if max_time is not None: 496 max_time += self.eas.GetRenderTime() 497 while self.State() not in (EAS_STATE_STOPPED, EAS_STATE_ERROR, EAS_STATE_EMPTY): 498 self.eas.Render() 499 if max_time is not None: 500 if self.eas.GetRenderTime() >= max_time: 501 eas_logger.info('Max render time exceeded - stopping playback') 502 self.Pause() 503 self.eas.Render() 504 break 505 506#--------------------------------------------------------------- 507# EAS_MIDIStream 508#--------------------------------------------------------------- 509class EAS_MIDIStream (EAS_Stream): 510 def Write(self, data): 511 """Write data to MIDI stream.""" 512 with self.eas.lock: 513 result = eas_dll.EAS_WriteMIDIStream(self.eas.handle, self.handle, data, len(data)) 514 if result: 515 raise EAS_Exception(result, 'EAS_WriteMIDIStream error %d' % result, 'EAS_WriteMIDIStream') 516 517 def Close (self): 518 """Close MIDI stream.""" 519 if hasattr(self, 'handle'): 520 with self.eas.lock: 521 eas_logger.debug('Call EAS_CloseMIDIStream') 522 result = eas_dll.EAS_CloseMIDIStream(self.eas.handle, self.handle) 523 if result: 524 raise EAS_Exception(result, 'EAS_CloseFile error %d' % result, 'EAS_CloseMIDIStream') 525 526 # remove file from the EAS object 527 self.eas.audio_streams.remove(self) 528 529 # clean up references 530 del self.handle 531 del self.eas 532 533#--------------------------------------------------------------- 534# EAS_Config 535#--------------------------------------------------------------- 536class EAS_Config (Structure): 537 _fields_ = [('libVersion', c_ulong), 538 ('checkedVersion', c_int), 539 ('maxVoices', c_long), 540 ('numChannels', c_long), 541 ('sampleRate', c_long), 542 ('mixBufferSize', c_long), 543 ('filterEnabled', c_int), 544 ('buildTimeStamp', c_ulong), 545 ('buildGUID', c_char_p)] 546 547#--------------------------------------------------------------- 548# EAS 549#--------------------------------------------------------------- 550class EAS (object): 551 def __init__ (self, handle=None, dll_path=None, log_file=None): 552 if eas_dll is None: 553 InitEASModule(dll_path) 554 if log_file is not None: 555 eas_logger.addHandler(log_file) 556 eas_logger.debug('EAS.__init__') 557 self.Init(handle) 558 559 def __del__ (self): 560 eas_logger.debug('EAS.__del__') 561 self.Shutdown() 562 563 def Init (self, handle=None): 564 """Initializes the EAS Library.""" 565 eas_logger.debug('EAS.Init') 566 567 # if we are already initialized, shutdown first 568 if hasattr(self, 'handle'): 569 eas_logger.debug('EAS.Init called with library already initalized') 570 self.ShutDown() 571 572 # setup the logging function 573 eas_dll.SetLogCallback(LogCallback) 574 575 # create some members 576 self.handle = c_void_p(0) 577 self.audio_streams = [] 578 self.output_streams = [] 579 self.aux_mixer = None 580 581 # create a sync lock 582 self.lock = threading.RLock() 583 with self.lock: 584 # set log callback 585 586 # get library configuration 587 self.Config() 588 589 # initialize library 590 if handle is None: 591 self.do_shutdown = True 592 eas_logger.debug('Call EAS_Init') 593 result = eas_dll.EAS_Init(byref(self.handle)) 594 if result: 595 raise EAS_Exception(result, 'EAS_Init error %d' % result, 'EAS_Init') 596 else: 597 self.do_shutdown = False 598 self.handle = handle 599 600 # allocate audio buffer for rendering 601 AudioBufferType = c_ubyte * (2 * self.config.mixBufferSize * self.config.numChannels) 602 self.audio_buffer = AudioBufferType() 603 self.buf_size = self.config.mixBufferSize 604 605 def Config (self): 606 """Retrieves the EAS library configuration""" 607 if not hasattr(self, 'config'): 608 eas_logger.debug('Call EAS_Config') 609 eas_dll.EAS_Config.restype = POINTER(EAS_Config) 610 self.config = eas_dll.EAS_Config()[0] 611 eas_logger.debug("libVersion=%08x, maxVoices=%d, numChannels=%d, sampleRate = %d, mixBufferSize=%d" % 612 (self.config.libVersion, self.config.maxVoices, self.config.numChannels, self.config.sampleRate, self.config.mixBufferSize)) 613 614 def Shutdown (self): 615 """Shuts down the EAS library""" 616 eas_logger.debug('EAS.Shutdown') 617 if hasattr(self, 'handle'): 618 with self.lock: 619 # close audio streams 620 audio_streams = self.audio_streams 621 for f in audio_streams: 622 eas_logger.warning('Stream was not closed before EAS_Shutdown') 623 f.Close() 624 625 # close output streams 626 output_streams = self.output_streams 627 for s in output_streams: 628 s.close() 629 630 # shutdown library 631 if self.do_shutdown: 632 eas_logger.debug('Call EAS_Shutdown') 633 result = eas_dll.EAS_Shutdown(self.handle) 634 if result: 635 raise EAS_Exception(result, 'EAS_Shutdown error %d' % result, 'EAS_Shutdown') 636 del self.handle 637 638 def OpenFile (self, path): 639 """Opens an audio file to be played by the EAS library and 640 returns an EAS_File object 641 642 Arguments: 643 path - path to audio file 644 645 Returns: 646 EAS_File 647 648 """ 649 with self.lock: 650 eas_logger.debug('Call EAS_OpenFile for file: %s' % path) 651 stream_handle = c_void_p(0) 652 result = eas_dll.EAS_OpenFile(self.handle, path, byref(stream_handle)) 653 if result: 654 raise EAS_Exception(result, 'EAS_OpenFile error %d on file %s' % (result, path), 'EAS_OpenFile') 655 656 # create file object and save in list 657 stream = EAS_File(path, stream_handle, self) 658 self.audio_streams.append(stream) 659 return stream 660 661 def OpenMIDIStream (self, stream=None): 662 """Opens a MIDI stream. 663 664 Arguments: 665 stream - open stream object. If None, a new synth 666 is created. 667 668 Returns: 669 EAS_MIDIStream 670 671 """ 672 with self.lock: 673 eas_logger.debug('Call EAS_OpenMIDIStream') 674 stream_handle = c_void_p(0) 675 if stream.handle is not None: 676 result = eas_dll.EAS_OpenMIDIStream(self.handle, byref(stream_handle), stream.handle) 677 else: 678 result = eas_dll.EAS_OpenMIDIStream(self.handle, byref(stream_handle), 0) 679 if result: 680 raise EAS_Exception(result, 'EAS_OpenMIDIStream error %d' % result, 'EAS_OpenMIDIStream') 681 682 # create stream object and save in list 683 stream = EAS_MIDIStream(stream_handle, self) 684 self.audio_streams.append(stream) 685 return stream 686 687 def OpenToneControlStream (self, path): 688 """Opens an MMAPI tone control file to be played by the EAS 689 library and returns an EAS_File object 690 691 Arguments: 692 path - path to audio file 693 694 Returns: 695 EAS_File 696 697 """ 698 with self.lock: 699 eas_logger.debug('Call EAS_MMAPIToneControl for file: %s' % path) 700 stream_handle = c_void_p(0) 701 result = eas_dll.EAS_MMAPIToneControl(self.handle, path, byref(stream_handle)) 702 if result: 703 raise EAS_Exception(result, 'EAS_MMAPIToneControl error %d on file %s' % (result, path), 'EAS_OpenToneControlStream') 704 705 # create file object and save in list 706 stream = EAS_File(path, stream_handle, self) 707 self.audio_streams.append(stream) 708 return stream 709 710 def Attach (self, stream): 711 """Attach a file or output device to the EAS output. 712 713 The stream object must support the following methods as 714 defined in the Python wave module: 715 close() 716 setparams() 717 writeframesraw() 718 719 Arguments: 720 stream - open wave object 721 722 """ 723 self.output_streams.append(stream) 724 stream.setparams((self.config.numChannels, 2, self.config.sampleRate, 0, 'NONE', None)) 725 726 def Detach (self, stream): 727 """Detach a file or output device from the EAS output. See 728 EAS.Attach for more details. It is the responsibility of 729 the caller to close the wave file or stream. 730 731 Arguments: 732 stream - open and attached wave object 733 """ 734 self.output_streams.remove(stream) 735 736 def StartWave (self, dev_num=0, sampleRate=None, maxBufSize=None): 737 """Route the audio output to the indicated wave device. Note 738 that this can cause EASDLL.EAS_RenderWaveOut to return an 739 error code if all the output buffers are full. In this case, 740 the render thread should sleep a bit and try again. 741 Unfortunately, due to the nature of the MMSYSTEM interface, 742 there is no simple way to suspend the render thread. 743 744 """ 745 if sampleRate == None: 746 sampleRate = self.config.sampleRate 747 if maxBufSize == None: 748 maxBufSize = self.config.mixBufferSize 749 with self.lock: 750 result = eas_dll.OpenWaveOutDevice(dev_num, sampleRate, maxBufSize) 751 if result: 752 raise EAS_Exception(result, 'OpenWaveOutDevice error %d' % result, 'OpenWaveOutDevice') 753 754 def StopWave (self): 755 """Stop routing audio output to the audio device.""" 756 with self.lock: 757 result = eas_dll.CloseWaveOutDevice() 758 if result: 759 raise EAS_Exception(result, 'CloseWaveOutDevice error %d' % result, 'CloseWaveOutDevice') 760 761 def Render (self, count=None, secs=None): 762 """Calls EAS_Render to render audio. 763 764 Arguments 765 count - number of buffers to render 766 secs - number of seconds to render 767 768 If both count and secs are None, render a single buffer. 769 770 """ 771 772 # determine number of buffers to render 773 if count is None: 774 if secs is not None: 775 count = int(secs * float(self.config.sampleRate) / float(self.buf_size) + 0.5) 776 else: 777 count = 1 778 779 # render buffers 780 eas_logger.debug('rendering %d buffers' % count) 781 samplesRendered = c_long(0) 782 with self.lock: 783 for c in range(count): 784 # render a buffer of audio 785 eas_logger.debug('rendering buffer') 786 while 1: 787 if self.aux_mixer is None: 788 result = eas_dll.EAS_RenderWaveOut(self.handle, byref(self.audio_buffer), self.buf_size, byref(samplesRendered)) 789 else: 790 result = eas_dll.EAS_RenderAuxMixer(self.handle, byref(self.audio_buffer), byref(samplesRendered)) 791 792 if result == 0: 793 break; 794 if result == EAS_BUFFER_FULL: 795 time.sleep(0.01) 796 else: 797 raise EAS_Exception(result, 'EAS_Render error %d' % result, 'EAS_Render') 798 799 # output to attached streams 800 for s in self.output_streams: 801 s.writeframesraw(self.audio_buffer) 802 803 def GetRenderTime (self): 804 """Get the render time in seconds.""" 805 eas_logger.debug('Call EAS_GetRenderTime') 806 msecs = c_int(0) 807 with self.lock: 808 result = eas_dll.EAS_GetRenderTime(self.handle, byref(msecs)) 809 if result: 810 raise EAS_Exception(result, 'EAS_GetRenderTime error %d' % result, 'EAS_GetRenderTime') 811 msecs = float(msecs.value) / 1000 812 eas_logger.debug('EAS_GetRenderTime: time=%.3f' % msecs) 813 return msecs 814 815 def SetVolume (self, volume): 816 """Set the master volume""" 817 eas_logger.debug('Call EAS_SetVolume: volume=%d' % volume) 818 with self.lock: 819 result = eas_dll.EAS_SetVolume(self.handle, 0, volume) 820 if result: 821 raise EAS_Exception(result, 'EAS_SetVolume error %d' % result, 'EAS_SetVolume') 822 823 def GetVolume (self): 824 """Get the stream volume.""" 825 eas_logger.debug('Call EAS_GetVolume') 826 volume = c_int(0) 827 with self.lock: 828 result = eas_dll.EAS_GetVolume(self.handle, 0, byref(volume)) 829 if result: 830 raise EAS_Exception(result, 'EAS_GetVolume error %d' % result, 'EAS_GetVolume') 831 eas_logger.debug('EAS_GetVolume: volume=%d' % volume.value) 832 return volume.value 833 834 def SetPolyphony (self, polyphony, synth_num=0): 835 """Set the polyphony of a synth.""" 836 eas_logger.debug('Call EAS_SetSynthPolyphony: synth_num=%d, polyphony=%d' % (synth_num, polyphony)) 837 with self.lock: 838 result = eas_dll.EAS_SetSynthPolyphony(self.handle, synth_num, polyphony) 839 if result: 840 raise EAS_Exception(result, 'EAS_SetSynthPolyphony error %d on synth %d' % (result, synth_num), 'EAS_SetPolyphony') 841 842 def GetPolyphony (self, synth_num=0): 843 """Get the polyphony of a synth.""" 844 eas_logger.debug('Call EAS_GetSynthPolyphony: synth_num=%d' % synth_num) 845 polyphony = c_int(0) 846 with self.lock: 847 result = eas_dll.EAS_GetSynthPolyphony(self.handle, synth_num, byref(polyphony)) 848 if result: 849 raise EAS_Exception(result, 'EAS_GetSynthPolyphony error %d on synth %d' % (result, synth_num), 'EAS_GetPolyphony') 850 eas_logger.debug('Call EAS_GetSynthPolyphony: synth_num=%d, polyphony=%d' % (synth_num, polyphony.value)) 851 return polyphony.value 852 853 def SetMaxLoad (self, max_load): 854 """Set the maximum parser load.""" 855 eas_logger.debug('Call EAS_SetMaxLoad: max_load=%d' % max_load) 856 with self.lock: 857 result = eas_dll.EAS_SetMaxLoad(self.handle, max_load) 858 if result: 859 raise EAS_Exception(result, 'EAS_SetMaxLoad error %d' % result, 'EAS_SetMaxLoad') 860 861 def SetParameter (self, module, param, value): 862 """Set a module parameter.""" 863 eas_logger.debug('Call EAS_SetParameter: module=%d, param=%d, value=%d' % (module, param, value)) 864 with self.lock: 865 result = eas_dll.EAS_SetParameter(self.handle, module, param, value) 866 if result: 867 raise EAS_Exception(result, 'EAS_SetParameter error %d (param=%d, value=%d)' % (result, param, value), 'EAS_SetParameter') 868 869 def GetParameter (self, module, param): 870 """Get the polyphony of a synth.""" 871 eas_logger.debug('Call EAS_GetParameter: module=%d, param=%d' % (module, param)) 872 value = c_int(0) 873 with self.lock: 874 result = eas_dll.EAS_GetParameter(self.handle, module, param, byref(value)) 875 if result: 876 raise EAS_Exception(result, 'EAS_SetParameter error %d (param=%d)' % (result, param), 'EAS_GetParameter') 877 eas_logger.debug('Call EAS_SetParameter: module=%d, param=%d, value=%d' % (module, param, value.value)) 878 return value.value 879 880 def SelectLib (self, test_lib=False): 881 eas_logger.debug('Call EAS_SelectLib: test_lib=%s' % test_lib) 882 easdll = cdll.LoadLibrary('EASDLL') 883 with self.lock: 884 result = eas_dll.EAS_SelectLib(self.handle, 0, test_lib) 885 if result: 886 raise EAS_Exception(result, 'EAS_SelectLib error %d' % result, 'EAS_SelectLib') 887 888 def LoadDLSCollection (self, path): 889 eas_logger.debug('Call EAS_LoadDLSCollection: lib_path=%s' % path) 890 with self.lock: 891 result = eas_dll.EAS_LoadDLSCollection(self.handle, 0, path) 892 if result: 893 raise EAS_Exception(result, 'EAS_LoadDLSCollection error %d lib %s' % (result, path), 'EAS_LoadDLSCollection') 894 895 def SetAuxMixerHook (self, aux_mixer): 896 897 # if aux mixer has bigger buffer, re-allocate buffer 898 if (aux_mixer is not None) and (aux_mixer.buf_size > self.config.mixBufferSize): 899 buf_size = aux_mixer.buf_size 900 else: 901 buf_size = self.config.mixBufferSize 902 903 # allocate audio buffer for rendering 904 AudioBufferType = c_ubyte * (2 * buf_size * self.config.numChannels) 905 self.audio_buffer = AudioBufferType() 906 self.buf_size = buf_size 907 self.aux_mixer = aux_mixer 908 909 def SetDebugLevel (self, level=3): 910 """Sets the EAS debug level.""" 911 with self.lock: 912 eas_logger.debug('Call EAS_SetDebugLevel') 913 eas_dll.EAS_DLLSetDebugLevel(self.handle, level) 914 915#--------------------------------------------------------------- 916# EASAuxMixer 917#--------------------------------------------------------------- 918class EASAuxMixer (object): 919 def __init__ (self, eas=None, num_streams=3, sample_rate=44100, max_sample_rate=44100): 920 eas_logger.debug('EASAuxMixer.__init__') 921 self.Init(eas, num_streams, sample_rate, max_sample_rate) 922 923 def __del__ (self): 924 eas_logger.debug('EASAuxMixer.__del__') 925 self.Shutdown() 926 927 def Init (self, eas=None, num_streams=3, sample_rate=44100, max_sample_rate=44100): 928 """Initializes the EAS Auxilliary Mixer.""" 929 eas_logger.debug('EASAuxMixer.Init') 930 931 if hasattr(self, 'eas'): 932 raise EAS_Exception(-1, 'EASAuxMixer already initialized', 'EASAuxMixer.Init') 933 934 # initialize EAS, if necessary 935 if eas is None: 936 eas_logger.debug('No EAS handle --- initializing EAS') 937 eas = EAS() 938 self.alloc_eas = True 939 else: 940 self.alloc_eas = False 941 self.eas = eas 942 943 # initialize library 944 eas_logger.debug('Call EAS_InitAuxMixer') 945 buf_size = c_int(0) 946 result = eas_dll.EAS_InitAuxMixer(eas.handle, num_streams, sample_rate, max_sample_rate, byref(buf_size)) 947 if result: 948 raise EAS_Exception(result, 'EAS_InitAuxMixer error %d' % result, 'EAS_InitAuxMixer') 949 self.buf_size = buf_size.value 950 self.streams = [] 951 eas.SetAuxMixerHook(self) 952 953 def Shutdown (self): 954 """Shuts down the EAS Auxilliary Mixer""" 955 eas_logger.debug('EASAuxMixer.Shutdown') 956 if not hasattr(self, 'eas'): 957 return 958 959 with self.eas.lock: 960 if len(self.streams): 961 eas_logger.warning('Stream was not closed before EAS_ShutdownAuxMixer') 962 for stream in self.streams: 963 self.CloseStream(stream) 964 965 self.eas.SetAuxMixerHook(None) 966 967 # shutdown library 968 eas_logger.debug('Call EAS_ShutdownAuxMixer') 969 result = eas_dll.EAS_ShutdownAuxMixer(self.eas.handle) 970 if result: 971 raise EAS_Exception(result, 'EAS_ShutdownAuxMixer error %d' % result, 'EAS_ShutdownAuxMixer') 972 973 # if we created the EAS reference here, shut it down 974 if self.alloc_eas: 975 self.eas.Shutdown() 976 self.alloc_eas = False 977 del self.eas 978 979 def OpenStream (self, decoder_func, inst_data, sample_rate, num_channels): 980 """Opens an audio file to be played by the JET library and 981 returns a JET_File object 982 983 Arguments: 984 callback - callback function to decode more audio 985 986 """ 987 with self.eas.lock: 988 eas_logger.debug('Call EAS_OpenAudioStream') 989 decoder_func = EAS_DECODER_FUNC(decoder_func) 990 stream_handle = c_void_p(0) 991 result = eas_dll.EAS_OpenAudioStream(self.eas.handle, decoder_func, inst_data, sample_rate, num_channels, stream_handle) 992 if result: 993 raise EAS_Exception(result, 'EAS_OpenAudioStream error %d on file %s' % (result, path), 'EAS_OpenAudioStream') 994 self.streams.add(stream_handle) 995 return stream_handle 996 997 def CloseStream (self, stream_handle): 998 """Closes an open audio stream.""" 999 with self.eas.lock: 1000 eas_logger.debug('Call EAS_CloseAudioStream') 1001 result = eas_dll.JET_CloseFile(self.eas.handle, stream_handle) 1002 if result: 1003 raise EAS_Exception(result, 'EAS_CloseAudioStream error %d' % result, 'EAS_CloseAudioStream') 1004 1005#--------------------------------------------------------------- 1006# JET_Status 1007#--------------------------------------------------------------- 1008class JET_Status (Structure): 1009 _fields_ = [('currentUserID', c_int), 1010 ('segmentRepeatCount', c_int), 1011 ('numQueuedSegments', c_int), 1012 ('paused', c_int), 1013 ('location', c_long), 1014 ('currentPlayingSegment', c_int), 1015 ('currentQueuedSegment', c_int), 1016 ] 1017 1018#--------------------------------------------------------------- 1019# JET_File 1020#--------------------------------------------------------------- 1021class JET_File (object): 1022 def __init__ (self, handle, jet): 1023 eas_logger.debug('JET_File.__init__') 1024 self.handle = handle 1025 self.jet = jet 1026 1027#--------------------------------------------------------------- 1028# JET 1029#--------------------------------------------------------------- 1030class JET (object): 1031 def __init__ (self, eas=None): 1032 # eas_logger.debug('JET.__init__') 1033 self.Init(eas) 1034 1035 def __del__ (self): 1036 eas_logger.debug('JET.__del__') 1037 self.Shutdown() 1038 1039 def Init (self, eas=None, config=None): 1040 """Initializes the JET Library.""" 1041 # eas_logger.debug('JET.Init') 1042 1043 if hasattr(self, 'eas'): 1044 raise EAS_Exception(-1, 'JET library already initialized', 'Jet.Init') 1045 1046 # create some members 1047 if eas is None: 1048 # eas_logger.debug('No EAS handle --- initializing EAS') 1049 eas = EAS() 1050 self.alloc_eas = True 1051 else: 1052 self.alloc_eas = False 1053 self.eas = eas 1054 self.fileOpen = False 1055 1056 # handle configuration 1057 if config is None: 1058 config_handle = c_void_p(0) 1059 config_size = 0 1060 else: 1061 jet_config = S_JET_CONFIG() 1062 jet_config.appLowNote = config.appLowNote 1063 config_handle = c_void_p(jet_config) 1064 config_size = jet_config.sizeof() 1065 1066 # initialize library 1067 # eas_logger.debug('Call JET_Init') 1068 result = eas_dll.JET_Init(eas.handle, config_handle, config_size) 1069 if result: 1070 raise EAS_Exception(result, 'JET_Init error %d' % result, 'JET_Init') 1071 1072 def Shutdown (self): 1073 """Shuts down the JET library""" 1074 eas_logger.debug('JET.Shutdown') 1075 if not hasattr(self, 'eas'): 1076 return 1077 1078 with self.eas.lock: 1079 if self.fileOpen: 1080 eas_logger.warning('Stream was not closed before JET_Shutdown') 1081 self.CloseFile() 1082 1083 # shutdown library 1084 eas_logger.debug('Call JET_Shutdown') 1085 result = eas_dll.JET_Shutdown(self.eas.handle) 1086 if result: 1087 raise EAS_Exception(result, 'JET_Shutdown error %d' % result, 'JET_Shutdown') 1088 1089 # if we created the EAS reference here, shut it down 1090 if self.alloc_eas: 1091 self.eas.Shutdown() 1092 self.alloc_eas = False 1093 del self.eas 1094 1095 def OpenFile (self, path): 1096 """Opens an audio file to be played by the JET library and 1097 returns a JET_File object 1098 1099 Arguments: 1100 path - path to audio file 1101 1102 """ 1103 with self.eas.lock: 1104 eas_logger.debug('Call JET_OpenFile for file: %s' % path) 1105 result = eas_dll.JET_OpenFile(self.eas.handle, path) 1106 if result: 1107 raise EAS_Exception(result, 'JET_OpenFile error %d on file %s' % (result, path), 'JET_OpenFile') 1108 1109 def CloseFile (self): 1110 """Closes an open audio file.""" 1111 with self.eas.lock: 1112 eas_logger.debug('Call JET_CloseFile') 1113 result = eas_dll.JET_CloseFile(self.eas.handle) 1114 if result: 1115 raise EAS_Exception(result, 'JET_CloseFile error %d' % result, 'JET_CloseFile') 1116 1117 def QueueSegment (self, userID, seg_num, dls_num=-1, repeat=0, tranpose=0, mute_flags=0): 1118 """Queue a segment for playback. 1119 1120 Arguments: 1121 seg_num - segment number to queue 1122 repeat - repeat count (-1=repeat forever, 0=no repeat, 1+ = play n+1 times) 1123 tranpose - transpose amount (+/-12) 1124 1125 """ 1126 with self.eas.lock: 1127 eas_logger.debug('Call JET_QueueSegment') 1128 result = eas_dll.JET_QueueSegment(self.eas.handle, seg_num, dls_num, repeat, tranpose, mute_flags, userID) 1129 if result: 1130 raise EAS_Exception(result, 'JET_QueueSegment error %d' % result, 'JET_QueueSegment') 1131 1132 def Clear_Queue(self): 1133 """Kills the queue.""" 1134 with self.eas.lock: 1135 eas_logger.debug('Call JET_Clear_Queue') 1136 result = eas_dll.JET_Clear_Queue(self.eas.handle) 1137 if result: 1138 raise EAS_Exception(result, 'JET_Clear_Queue error %d' % result, 'JET_Clear_Queue') 1139 1140 def GetAppEvent(self): 1141 """Gets an App event.""" 1142 with self.eas.lock: 1143 eas_logger.debug('Call JET_GetEvent') 1144 result = eas_dll.JET_GetEvent(self.eas.handle, 0, 0) 1145 return result 1146 1147 def Play(self): 1148 """Starts JET playback.""" 1149 with self.eas.lock: 1150 eas_logger.debug('Call JET_Play') 1151 result = eas_dll.JET_Play(self.eas.handle) 1152 if result: 1153 raise EAS_Exception(result, 'JET_Play error %d' % result, 'JET_Play') 1154 1155 def Pause(self): 1156 """Pauses JET playback.""" 1157 with self.eas.lock: 1158 eas_logger.debug('Call JET_Pause') 1159 result = eas_dll.JET_Pause(self.eas.handle) 1160 if result: 1161 raise EAS_Exception(result, 'JET_Pause error %d' % result, 'JET_Pause') 1162 1163 def Render (self, count=None, secs=None): 1164 """Calls EAS_Render to render audio. 1165 1166 Arguments 1167 count - number of buffers to render 1168 secs - number of seconds to render 1169 1170 If both count and secs are None, render a single buffer. 1171 1172 """ 1173 # calls JET.Render 1174 with self.eas.lock: 1175 self.eas.Render(count, secs) 1176 1177 def Status (self): 1178 """Get JET status.""" 1179 with self.eas.lock: 1180 eas_logger.debug('Call JET_Status') 1181 status = JET_Status() 1182 result = eas_dll.JET_Status(self.eas.handle, byref(status)) 1183 if result: 1184 raise EAS_Exception(result, 'JET_Status error %d' % result, 'JET_Status') 1185 eas_logger.debug("currentUserID=%d, repeatCount=%d, numQueuedSegments=%d, paused=%d" % 1186 (status.currentUserID, status.segmentRepeatCount, status.numQueuedSegments, status.paused)) 1187 return status 1188 1189 def SetVolume (self, volume): 1190 """Set the JET volume""" 1191 eas_logger.debug('Call JET_SetVolume') 1192 with self.eas.lock: 1193 result = eas_dll.JET_SetVolume(self.eas.handle, volume) 1194 if result: 1195 raise EAS_Exception(result, 'JET_SetVolume error %d' % result, 'JET_SetVolume') 1196 1197 def SetTransposition (self, transposition): 1198 """Set the transposition of a stream.""" 1199 eas_logger.debug('Call JET_SetTransposition') 1200 with self.eas.lock: 1201 result = eas_dll.JET_SetTransposition(self.eas.handle, transposition) 1202 if result: 1203 raise EAS_Exception(result, 'JET_SetTransposition error %d' % result, 'JET_SetTransposition') 1204 1205 def TriggerClip (self, clipID): 1206 """Trigger a clip in the current segment.""" 1207 eas_logger.debug('Call JET_TriggerClip') 1208 with self.eas.lock: 1209 result = eas_dll.JET_TriggerClip(self.eas.handle, clipID) 1210 if result: 1211 raise EAS_Exception(result, 'JET_SetTransposition error %d' % result, 'JET_TriggerClip') 1212 1213 def SetMuteFlag (self, track_num, mute, sync=True): 1214 """Trigger a clip in the current segment.""" 1215 eas_logger.debug('Call JET_SetMuteFlag') 1216 with self.eas.lock: 1217 result = eas_dll.JET_SetMuteFlag(self.eas.handle, track_num, mute, sync) 1218 if result: 1219 raise EAS_Exception(result, 'JET_SetMuteFlag error %d' % result, 'JET_SetMuteFlag') 1220 1221 def SetMuteFlags (self, mute_flags, sync=True): 1222 """Trigger a clip in the current segment.""" 1223 eas_logger.debug('Call JET_SetMuteFlags') 1224 with self.eas.lock: 1225 result = eas_dll.JET_SetMuteFlags(self.eas.handle, mute_flags, sync) 1226 if result: 1227 raise EAS_Exception(result, 'JET_SetMuteFlag error %d' % result, 'JET_SetMuteFlags') 1228 1229 1230