VERSION 1.0 CLASS BEGIN MultiUse = -1 'True Persistable = 0 'NotPersistable DataBindingBehavior = 0 'vbNone DataSourceBehavior = 0 'vbNone MTSTransactionMode = 0 'NotAnMTSObject END Attribute VB_Name = "cEventStream" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = True Attribute VB_PredeclaredId = False Attribute VB_Exposed = False Option Explicit ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Objeto responsável por carregar e armazenar eventos ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Guarda o nome do objeto Private Const ST_MY_NAME As String = "cEventStream" ' Diferença mínima para fazer mix entre timers Private Const LN_MIN_MIX_TIME As Long = 100 ' Tipo evento Private Type EVENT_INFO ctTime As cTime lnLine As Long lnWord As Long End Type ' Eventos Private ln_AuxEventIndex As Long Private ln_EventIndex As Long ' Tempos de eventos próximos Private ln_LastEventTime As Long Private ln_NextEventTime As Long ' Vetor de eventos Private vtei_Events() As EVENT_INFO Private ln_NumEvents As Long ' Auxiliares ao QuickSort, Swap e retorno Private ei_SwapAux As EVENT_INFO Private ei_QSPivo As EVENT_INFO ' Evento de quando há evento a executar Public Event LoadEvent(lnLine As Long, lnWord As Long) ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Retorna um evento a ser processado dado um tempo (sequencial) ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Sub UpdateTimeEvent() ' Se o tempo estiver maior que o escopo atual If (ln_TrackPosition >= ln_NextEventTime) Then ' Procura pelo próximo evento SetNextEvent ' Atualiza RaiseEvent LoadEvent(vtei_Events(ln_EventIndex).lnLine, vtei_Events(ln_EventIndex).lnWord) ' Se o tempo estiver menor que o escopo atual ElseIf (ln_TrackPosition < ln_LastEventTime) Then ' Procura SetPrevEvent ' Atualiza RaiseEvent LoadEvent(vtei_Events(ln_EventIndex).lnLine, vtei_Events(ln_EventIndex).lnWord) End If End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Seta qual o próximo evento a ser processado ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Sub SetNextEvent() On Error GoTo ErrTreat: ' Seta evento ln_AuxEventIndex = ln_EventIndex ' Enquanto o tempo atual for maior While (ln_TrackPosition >= ln_NextEventTime) ' Guarda evento ln_EventIndex = ln_AuxEventIndex ' Guarda o tempo do último evento ln_LastEventTime = ln_NextEventTime ' Seta o próximo evento ln_AuxEventIndex = ln_AuxEventIndex + 1 ' Verifica se o próximo evento existe If (ln_AuxEventIndex < ln_NumEvents) Then ' Seta o tempo do próximo evento ln_NextEventTime = vtei_Events(ln_AuxEventIndex).ctTime.Time Else ' Seta tempo 'infinito' ln_NextEventTime = LN_LIMIT_VALUE End If Wend Exit Sub ErrTreat: LogErrMessage Err.Description, ST_MY_NAME + ".SetNextEvent" End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Seta qual o evento anterior a ser processado ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Sub SetPrevEvent() On Error GoTo ErrTreat: ' Seta evento ln_AuxEventIndex = ln_EventIndex ' Enquanto o tempo atual for menor While (ln_TrackPosition < ln_LastEventTime) ' Seta tempo do próximo evento como sendo o atual ln_NextEventTime = ln_LastEventTime ' Seta evento anterior ln_AuxEventIndex = ln_AuxEventIndex - 1 ' Verifica se o evento anterior existe If (ln_AuxEventIndex >= 0) Then ' Seta evento ln_EventIndex = ln_AuxEventIndex ' Seta tempo do evento ln_LastEventTime = vtei_Events(ln_AuxEventIndex).ctTime.Time Else ' Seta o tempo do evento como sendo mínimo ln_LastEventTime = LN_INVALID_VALUE End If Wend Exit Sub ErrTreat: LogErrMessage Err.Description, ST_MY_NAME + ".SetPrevEvent" End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Propriedade de carregamento ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Property Let Load(clInput As cLyric) On Error GoTo ErrTreat: Dim lnI As Long, lnJ As Long, lnK As Long Dim llLine As cLyricLine Dim lwWord As cLyricWord ' Reseta stream Reset ' Percorre a lista de linhas For lnI = 0 To (clInput.GetLineSize - 1) ' Pega a linha Set llLine = clInput.GetLine(lnI) ' Varre a lista de tempos For lnJ = 0 To (llLine.GetTimeSize - 1) ' Adiciona evento de linha AddEvent lnI, LN_INVALID_VALUE, llLine.GetTime(lnJ) Next lnJ ' Varre a lista de words For lnK = 0 To (llLine.GetWordSize - 1) ' Pega a word Set lwWord = llLine.GetWord(lnK) ' Varre a lista de tempos For lnJ = 0 To (lwWord.GetTimeSize - 1) ' Verifica se tempo é válido If (lwWord.GetTime(lnJ).Time > 0) Then ' Adiciona evento da word AddEvent lnI, lnK, lwWord.GetTime(lnJ) End If Next lnJ Next lnK Next lnI ' Verifica se encontrou pelo menos um evento If (ln_NumEvents > 0) Then ' Ordena vetor de eventos QuickSort 0, (ln_NumEvents - 1) ' Seta como tempo do próximo evento como sendo o início do primeiro evento ln_NextEventTime = vtei_Events(0).ctTime.Time End If ' Libera apontamento Set llLine = Nothing Exit Property ErrTreat: LogErrMessage Err.Description, ST_MY_NAME + ".Load [let]" End Property ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Destorce o tempo dos eventos dado dois timers ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Sub TimeMix(lnBase As Long, lnNew As Long) Dim dbDiff As Double Dim lnI As Long, lnJ As Long On Error GoTo ErrTreat: ' Se a diferença entre os dois timers for maior que o mínimo If ((Abs(lnBase) - Abs(lnNew)) > LN_MIN_MIX_TIME) And (lnBase > LN_NEUTRAL_VALUE) And (lnNew > LN_NEUTRAL_VALUE) Then ' Calcula diferença entre eles dbDiff = lnNew / lnBase ' Último evento lnJ = ln_NumEvents - 1 ' Varre lista de eventos For lnI = 0 To lnJ ' Recalcula tempo vtei_Events(lnI).ctTime.Time = vtei_Events(lnI).ctTime.Time * dbDiff Next lnI End If Exit Sub ErrTreat: LogErrMessage Err.Description, ST_MY_NAME + ".TimeMix" End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Procedimento que adiciona um novo evento à lista ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Sub AddEvent(lnLine As Long, lnWord As Long, ctTime As cTime) Dim eiAux As EVENT_INFO On Error GoTo ErrTreat: ' Seta valores eiAux.lnLine = lnLine Set eiAux.ctTime = ctTime eiAux.lnWord = lnWord ' Redimenciona vetor ReDim Preserve vtei_Events(ln_NumEvents) ' Armazena info vtei_Events(ln_NumEvents) = eiAux ' Incrementa contador ln_NumEvents = ln_NumEvents + 1 Exit Sub ErrTreat: LogErrMessage Err.Description, ST_MY_NAME + ".AddEvent" End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Ordena o vetor por Quicksort ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Sub QuickSort(lnStart As Long, lnEnd As Long) Dim lnI As Long, lnJ As Long On Error GoTo ErrTreat: ' Verifica se continua a recursividade If (lnEnd > lnStart) Then ' Seta valores inicial e final lnI = lnStart lnJ = lnEnd ' Calcula e seta o pivo ei_QSPivo = vtei_Events((lnI + lnJ) / 2) ' Enquanto tiver elementos maiores do lado direito e menores do lado esquerdo While (lnI <= lnJ) ' Encontra maior valor While vtei_Events(lnI).ctTime.Time < ei_QSPivo.ctTime.Time lnI = lnI + 1 Wend ' Encontra menor valor While ei_QSPivo.ctTime.Time < vtei_Events(lnJ).ctTime.Time lnJ = lnJ - 1 Wend ' Se menor valor está à direita If (lnI <= lnJ) Then ' Trocam de posição Swap lnI, lnJ ' Incrementa posição lnI = lnI + 1 lnJ = lnJ - 1 End If Wend ' Ordena a parte da esquerda (por recursividade) QuickSort lnStart, lnJ ' Ordena a parta da direita (por recursividade) QuickSort lnI, lnEnd End If Exit Sub ErrTreat: LogErrMessage Err.Description, ST_MY_NAME + ".QuickSort" End Sub Private Sub Swap(Index1 As Long, Index2 As Long) On Error Resume Next ' Copia do 1 para aux ei_SwapAux = vtei_Events(Index1) ' Copia do 2 para o 1 vtei_Events(Index1) = vtei_Events(Index2) ' Copia do aux pro 2 vtei_Events(Index2) = ei_SwapAux End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Reseta stream ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Sub Reset() ' Esvazia vetor Erase vtei_Events() ' Inicia valores ln_EventIndex = 0 ln_NumEvents = 0 ln_LastEventTime = LN_INVALID_VALUE ln_NextEventTime = LN_LIMIT_VALUE End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Propriedade do número de eventos ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Property Get NumEvents() As Long ' Retorna o número de eventos NumEvents = ln_NumEvents End Property ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Procedimentos de criação e destruição do objeto ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Sub Class_Initialize() ' Inicia valores ln_NumEvents = LN_NEUTRAL_VALUE End Sub Private Sub Class_Terminate() Dim lnI As Long, lnJ As Long ' Último evento lnJ = ln_NumEvents - 1 ' Varre lista de eventos For lnI = 0 To lnJ ' Libera tempo Set vtei_Events(lnI).ctTime = Nothing Next lnI ' Esvazia vetor Erase vtei_Events() End Sub