CItem* EventCanvas::getRightMostSelected() { iCItem i, iRightmost; CItem* rightmost = NULL; // get a list of items that belong to the current part // since multiple parts have populated the _items list // we need to filter on the actual current Part! CItemList list = _items; if(multiPartSelectionAction && !multiPartSelectionAction->isChecked()) list = getItemlistForCurrentPart(); //CItemList list = getItemlistForCurrentPart(); //Get the rightmost selected note (if any) i = list.begin(); while (i != list.end()) { if (i->second->isSelected()) { iRightmost = i; rightmost = i->second; } ++i; } return rightmost; }
CItem* EventCanvas::getLeftMostSelected() { iCItem i, iLeftmost; CItem* leftmost = NULL; // get a list of items that belong to the current part // since multiple parts have populated the _items list // we need to filter on the actual current Part! //CItemList list = getItemlistForCurrentPart(); CItemList list = _items; if(multiPartSelectionAction && !multiPartSelectionAction->isChecked()) list = getItemlistForCurrentPart(); if (list.size() > 0) { i = list.end(); while (i != list.begin()) { --i; if (i->second->isSelected()) { iLeftmost = i; leftmost = i->second; } } } return leftmost; }
QList<Event> AbstractMidiEditor::getSelectedEvents()/*{{{*/ { QList<Event> rv; if(canvas) { CItemList list = canvas->getSelectedItemsForCurrentPart(); for (iCItem k = list.begin(); k != list.end(); ++k) { NEvent* nevent = (NEvent*) (k->second); Event event = nevent->event(); if (event.type() != Note) continue; rv.append(event); } } return rv; }/*}}}*/
void EventCanvas::selectAtTick(unsigned int tick)/*{{{*/ { CItemList list = _items; if(multiPartSelectionAction && !multiPartSelectionAction->isChecked()) list = getItemlistForCurrentPart(); //CItemList list = getItemlistForCurrentPart(); //Select note nearest tick, if none selected and there are any if (!list.empty() && selectionSize() == 0) { iCItem i = list.begin(); CItem* nearest = i->second; while (i != list.end()) { CItem* cur = i->second; unsigned int curtk = abs(cur->x() + cur->part()->tick() - tick); unsigned int neartk = abs(nearest->x() + nearest->part()->tick() - tick); if (curtk < neartk) { nearest = cur; } i++; } if (!nearest->isSelected()) { selectItem(nearest, true); if(editor->isGlobalEdit()) populateMultiSelect(nearest); songChanged(SC_SELECTION); } itemPressed(nearest); m_tempPlayItems.append(nearest); QTimer::singleShot(NOTE_PLAY_TIME, this, SLOT(playReleaseForItem())); } }/*}}}*/
void EventCanvas::populateMultiSelect(CItem* baseItem)/*{{{*/ { if(editor->isGlobalEdit() && baseItem) { PartList* pl = editor->parts(); int curTranspose = ((MidiTrack*)baseItem->part()->track())->getTransposition(); Event curEvent = baseItem->event(); int curPitch = curEvent.pitch(); int curRawPitch = curPitch - curTranspose; //int curLen = curEvent.lenTick(); m_multiSelect.clear(); for(iPart p = pl->begin(); p != pl->end(); ++p) { if(p->second == _curPart) continue; CItemList pitems = getItemlistForPart(p->second); for (iCItem i = pitems.begin(); i != pitems.end(); ++i) { MidiTrack* mtrack = (MidiTrack*)i->second->part()->track(); int transp = mtrack->getTransposition(); Event e = i->second->event(); if(e.empty()) continue; int pitch = e.pitch(); int rpitch = pitch - transp; //int len = e.lenTick(); //printf("Current pitch: %d, rawpitch: %d - note pitch: %d, raw: %d\n", curPitch, curRawPitch, pitch, rpitch); if(e.tick() == curEvent.tick() && rpitch == curRawPitch/*, len == curLen*/) { m_multiSelect.add(i->second); break; } } } //printf("MultiSelect list size: %d \n", (int)m_multiSelect.size()); } }/*}}}*/
void EventCanvas::actionCommand(int action)/*{{{*/ { switch(action) { case LOCATORS_TO_SELECTION: { int tick_max = 0; int tick_min = INT_MAX; bool found = false; for (iCItem i = _items.begin(); i != _items.end(); i++) { if (!i->second->isSelected()) continue; int tick = i->second->x(); int len = i->second->event().lenTick(); found = true; if (tick + len > tick_max) tick_max = tick + len; if (tick < tick_min) tick_min = tick; } if (found) { Pos p1(tick_min, true); Pos p2(tick_max, true); song->setPos(1, p1); song->setPos(2, p2); } } break; case SEL_RIGHT ... SEL_RIGHT_ADD: { if (action == SEL_RIGHT && allItemsAreSelected()) { deselectAll(); selectAtTick(song->cpos()); return; } iCItem i, iRightmost; CItem* rightmost = NULL; // get a list of items that belong to the current part // since multiple parts have populated the _items list // we need to filter on the actual current Part! CItemList list = _items; if(multiPartSelectionAction && !multiPartSelectionAction->isChecked()) list = getItemlistForCurrentPart(); //Get the rightmost selected note (if any) i = list.begin(); while (i != list.end()) { if (i->second->isSelected()) { iRightmost = i; rightmost = i->second; } ++i; } if (rightmost) { iCItem temp = iRightmost; temp++; //If so, deselect current note and select the one to the right if (temp != list.end()) { if (action != SEL_RIGHT_ADD) deselectAll(); iRightmost++; iRightmost->second->setSelected(true); itemPressed(iRightmost->second); m_tempPlayItems.append(iRightmost->second); QTimer::singleShot(NOTE_PLAY_TIME, this, SLOT(playReleaseForItem())); if(editor->isGlobalEdit()) populateMultiSelect(iRightmost->second); updateSelection(); } } else // there was no item selected at all? Then select nearest to tick if there is any { selectAtTick(song->cpos()); updateSelection(); } } break; case SEL_LEFT ... SEL_LEFT_ADD: { if (action == SEL_LEFT && allItemsAreSelected()) { deselectAll(); selectAtTick(song->cpos()); return; } iCItem i, iLeftmost; CItem* leftmost = NULL; // get a list of items that belong to the current part // since multiple parts have populated the _items list // we need to filter on the actual current Part! CItemList list = _items; if(multiPartSelectionAction && !multiPartSelectionAction->isChecked()) list = getItemlistForCurrentPart(); if (list.size() > 0) { i = list.end(); while (i != list.begin()) { --i; if (i->second->isSelected()) { iLeftmost = i; leftmost = i->second; } } if (leftmost) { if (iLeftmost != list.begin()) { //Add item if (action != SEL_LEFT_ADD) deselectAll(); iLeftmost--; iLeftmost->second->setSelected(true); itemPressed(iLeftmost->second); m_tempPlayItems.append(iLeftmost->second); QTimer::singleShot(NOTE_PLAY_TIME, this, SLOT(playReleaseForItem())); if(editor->isGlobalEdit()) populateMultiSelect(iLeftmost->second); updateSelection(); } else { leftmost->setSelected(true); itemPressed(leftmost); m_tempPlayItems.append(leftmost); QTimer::singleShot(NOTE_PLAY_TIME, this, SLOT(playReleaseForItem())); if(editor->isGlobalEdit()) populateMultiSelect(leftmost); updateSelection(); } } else // there was no item selected at all? Then select nearest to tick if there is any { selectAtTick(song->cpos()); updateSelection(); } } } break; case INC_PITCH_OCTAVE: { modifySelected(NoteInfo::VAL_PITCH, 12); } break; case DEC_PITCH_OCTAVE: { modifySelected(NoteInfo::VAL_PITCH, -12); } break; case INC_PITCH: { modifySelected(NoteInfo::VAL_PITCH, 1); } break; case DEC_PITCH: { modifySelected(NoteInfo::VAL_PITCH, -1); } break; case INC_POS: { // TODO: Check boundaries modifySelected(NoteInfo::VAL_TIME, editor->raster()); } break; case DEC_POS: { // TODO: Check boundaries modifySelected(NoteInfo::VAL_TIME, 0 - editor->raster()); } break; case INCREASE_LEN: { // TODO: Check boundaries modifySelected(NoteInfo::VAL_LEN, editor->raster()); } break; case DECREASE_LEN: { // TODO: Check boundaries modifySelected(NoteInfo::VAL_LEN, 0 - editor->raster()); } break; case GOTO_SEL_NOTE: { CItem* leftmost = getLeftMostSelected(); if (leftmost) { unsigned newtick = leftmost->event().tick() + leftmost->part()->tick(); Pos p1(newtick, true); song->setPos(0, p1, true, true, false); } } break; case MIDI_PANIC: { song->panic(); } break; } }/*}}}*/
void EventCanvas::viewMousePressEvent(QMouseEvent* event)/*{{{*/ { ///keyState = event->state(); _keyState = ((QInputEvent*) event)->modifiers(); _button = event->button(); //printf("viewMousePressEvent buttons:%x mods:%x button:%x\n", (int)event->buttons(), (int)keyState, event->button()); // special events if right button is clicked while operations // like moving or drawing lasso is performed. if (event->buttons() & Qt::RightButton & ~(event->button())) { //printf("viewMousePressEvent special buttons:%x mods:%x button:%x\n", (int)event->buttons(), (int)keyState, event->button()); switch (_drag) { case DRAG_LASSO: _drag = DRAG_OFF; redraw(); return; case DRAG_MOVE: _drag = DRAG_OFF; endMoveItems(_start, MOVE_MOVE, 0); return; default: break; } } // ignore event if (another) button is already active: if (event->buttons() & (Qt::LeftButton | Qt::RightButton | Qt::MidButton) & ~(event->button())) { //printf("viewMousePressEvent ignoring buttons:%x mods:%x button:%x\n", (int)event->buttons(), (int)keyState, event->button()); return; } bool shift = _keyState & Qt::ShiftModifier; bool alt = _keyState & Qt::AltModifier; bool ctrl = _keyState & Qt::ControlModifier; _start = event->pos(); //--------------------------------------------------- // set curItem to item mouse is pointing // (if any) //--------------------------------------------------- CItemList list = _items; if(multiPartSelectionAction && !multiPartSelectionAction->isChecked()) list = getItemlistForCurrentPart(); if (virt()) { _curItem = list.find(_start);//_items.find(_start); } else { _curItem = 0; //selectAtTick(_start.x()); iCItem ius; bool usfound = false; for (iCItem i = list.begin(); i != list.end(); ++i) { MidiTrack* mtrack = (MidiTrack*)i->second->part()->track(); int sy = _start.y(); int p = y2pitch(sy); if(editor->isGlobalEdit()) p += mtrack->getTransposition(); int p2 = pitch2y(p); QPoint lpos(_start.x(), p2); QRect box = i->second->bbox(); int x = rmapxDev(box.x()); int y = rmapyDev(box.y()); int w = rmapxDev(box.width()); int h = rmapyDev(box.height()); QRect r(x, y, w, h); r.translate(i->second->pos().x(), i->second->pos().y()); if(r.contains(lpos)) { if (i->second->isSelected()) { _curItem = i->second; break; } else if (!usfound) { ius = i; usfound = true; } } } if (!_curItem && usfound) _curItem = ius->second; } if(editor->isGlobalEdit() && _curItem) { populateMultiSelect(_curItem); } if (_curItem && (event->button() == Qt::MidButton)) { if (!_curItem->isSelected()) { selectItem(_curItem, true); updateSelection(); redraw(); } startDrag(_curItem, shift); } else if (event->button() == Qt::RightButton) { if (_curItem) { if (shift) { _drag = DRAG_RESIZE; setCursor(); int dx = _start.x() - _curItem->x(); _curItem->setWidth(dx); _start.setX(_curItem->x()); deselectAll(); selectItem(_curItem, true); updateSelection(); redraw(); } else { _itemPopupMenu = genItemPopup(_curItem); if (_itemPopupMenu) { QAction *act = _itemPopupMenu->exec(QCursor::pos()); if (act) itemPopup(_curItem, act->data().toInt(), _start); delete _itemPopupMenu; } } } else { _canvasPopupMenu = genCanvasPopup(true); if (_canvasPopupMenu) { QAction *act = _canvasPopupMenu->exec(QCursor::pos(), 0); if (act) { int actnum = act->data().toInt(); canvasPopup(actnum); if(actnum >= 20) //Nome of the tools have a higher number than 9 { editor->updateCanvas(); los->arranger->updateCanvas(); } } delete _canvasPopupMenu; } } } else if (event->button() == Qt::LeftButton) { switch (_tool) { case PointerTool: if (_curItem) { /*if (_curItem->part() != _curPart) { _curPart = _curItem->part(); _curPartId = _curPart->sn(); curPartChanged(); }*/ itemPressed(_curItem); if (shift) _drag = DRAG_COPY_START; else if (alt) { _drag = DRAG_CLONE_START; } else if (ctrl) { //Select all on the same pitch (e.g. same y-value) deselectAll(); //printf("Yes, ctrl and press\n"); for (iCItem i = _items.begin(); i != _items.end(); ++i) { if (i->second->y() == _curItem->y()) selectItem(i->second, true); } updateSelection(); redraw(); } else _drag = DRAG_MOVE_START; } else _drag = DRAG_LASSO_START; setCursor(); break; case RubberTool: deleteItem(_start); _drag = DRAG_DELETE; setCursor(); break; case PencilTool: if (_curItem) { _drag = DRAG_RESIZE; setCursor(); int dx = _start.x() - _curItem->x(); _curItem->setWidth(dx); _start.setX(_curItem->x()); } else { _drag = DRAG_NEW; setCursor(); _curItem = newItem(_start, event->modifiers()); if (_curItem) _items.add(_curItem); else { _drag = DRAG_OFF; setCursor(); } } deselectAll(); if (_curItem) { selectItem(_curItem, true); // Play the note itemPressed(_curItem); } updateSelection(); redraw(); break; default: break; } } mousePress(event); }/*}}}*/
/***************************************************************************** * CTTSEngObj::AddNextSentItem * *-----------------------------* * Locates the next sentence item in the stream and adds it to the list. * Returns true if the last item added is the end of the sentence. ****************************************************************************/ BOOL CTTSEngObj::AddNextSentItem( CItemList& ItemList ) { //--- Get the token ULONG ulIndex; CSentItem Item; Item.pItem = FindNextToken( m_pNextChar, m_pEndChar, m_pNextChar ); //--- This case can occur when we hit the end of a text fragment. // Returning at this point will cause advancement to the next fragment. if( Item.pItem == NULL ) { return false; } const WCHAR* pTrailChar = m_pNextChar-1; ULONG TokenLen = m_pNextChar - Item.pItem; //--- Split off leading punction if any static const WCHAR LeadItems[] = { L'(', L'\"', L'{', L'\'', L'[' }; while( TokenLen > 1 ) { if( SearchSet( Item.pItem[0], LeadItems, sp_countof(LeadItems), &ulIndex ) ) { CSentItem LItem; LItem.pItem = Item.pItem; LItem.ulItemLen = 1; LItem.pXmlState = &m_pCurrFrag->State; LItem.ulItemSrcLen = LItem.ulItemLen; LItem.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset + ( LItem.pItem - m_pCurrFrag->pTextStart ); ItemList.AddTail( LItem ); ++Item.pItem; --TokenLen; } else { break; } } //--- Get primary item insert position SPLISTPOS ItemPos = ItemList.AddTail( Item ); //--- Split off trailing punction if any. static const WCHAR EOSItems[] = { L'.', L'!', L'?' }; static const WCHAR TrailItems[] = { L',', L'\"', L';', L':', L')', L'}', L'\'', L']' }; SPLISTPOS NextPos = NULL; BOOL fIsEOS = false; while( TokenLen > 1 ) { BOOL fAddTrailItem = false; if( SearchSet( *pTrailChar, EOSItems, sp_countof(EOSItems), &ulIndex ) ) { fIsEOS = true; fAddTrailItem = true; } else if( SearchSet( *pTrailChar, TrailItems, sp_countof(TrailItems), &ulIndex ) ) { fAddTrailItem = true; } if( fAddTrailItem ) { CSentItem TItem; TItem.pItem = pTrailChar; TItem.ulItemLen = 1; TItem.pXmlState = &m_pCurrFrag->State; TItem.ulItemSrcLen = TItem.ulItemLen; TItem.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset + ( TItem.pItem - m_pCurrFrag->pTextStart ); NextPos = ItemList.InsertAfter( ItemPos, TItem ); --TokenLen; --pTrailChar; } else { break; } } //--- Abreviation or sentence end? // If we are at the end of the buffer then EOS is implied. if( *m_pNextChar == NULL ) { fIsEOS = true; if( !SearchSet( *(m_pNextChar-1), EOSItems, sp_countof(EOSItems), &ulIndex ) ) { //--- Terminate with a period if we are at the end of a buffer // and no end of sentence punction has been added. static const WCHAR* pPeriod = L"."; CSentItem EOSItem; EOSItem.pItem = pPeriod; EOSItem.ulItemLen = 1; EOSItem.pXmlState = &m_pCurrFrag->State; EOSItem.ulItemSrcLen = EOSItem.ulItemLen; EOSItem.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset + ( (m_pNextChar-1) - m_pCurrFrag->pTextStart ); ItemList.AddTail( EOSItem ); } } else if( pTrailChar[1] == L'.' ) { //--- Here is where you would try to prove that it's not EOS // It might be an abreviation. That's a hard problem that // we are not going to attempt here. } //--- Substitute underscore for apostrophe for( ULONG i = 0; i < TokenLen; ++i ) { if( Item.pItem[i] == L'\'' ) { ((WCHAR)Item.pItem[i]) = L'_'; } } //--- Add the main item if( TokenLen > 0 ) { Item.ulItemLen = TokenLen; Item.pXmlState = &m_pCurrFrag->State; Item.ulItemSrcLen = Item.ulItemLen; Item.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset + ( Item.pItem - m_pCurrFrag->pTextStart ); ItemList.SetAt( ItemPos, Item ); } return fIsEOS; } /* CTTSEngObj::AddNextSentItem */
/***************************************************************************** * CTTSEngObj::GetNextSentence * *-----------------------------* * This method is used to create a list of items to be spoken. ****************************************************************************/ HRESULT CTTSEngObj::GetNextSentence( CItemList& ItemList ) { HRESULT hr = S_OK; //--- Clear the destination ItemList.RemoveAll(); //--- Is there any work to do if( m_pCurrFrag == NULL ) { hr = S_FALSE; } else { BOOL fSentDone = false; BOOL fGoToNextFrag = false; while( m_pCurrFrag && !fSentDone ) { if( m_pCurrFrag->State.eAction == SPVA_Speak ) { fSentDone = AddNextSentItem( ItemList ); //--- Advance fragment? if( m_pNextChar >= m_pEndChar ) { fGoToNextFrag = true; } } else { //--- Add non spoken fragments CSentItem Item; Item.pItem = m_pCurrFrag->pTextStart; Item.ulItemLen = m_pCurrFrag->ulTextLen; Item.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset; Item.ulItemSrcLen = Item.ulItemLen; Item.pXmlState = &m_pCurrFrag->State; ItemList.AddTail( Item ); fGoToNextFrag = true; } if( fGoToNextFrag ) { fGoToNextFrag = false; m_pCurrFrag = m_pCurrFrag->pNext; if( m_pCurrFrag ) { m_pNextChar = m_pCurrFrag->pTextStart; m_pEndChar = m_pNextChar + m_pCurrFrag->ulTextLen; } else { m_pNextChar = NULL; m_pEndChar = NULL; } } } // end while if( ItemList.IsEmpty() ) { hr = S_FALSE; } } return hr; } /* CTTSEngObj::GetNextSentence */
/***************************************************************************** * CTTSEngObj::OutputSentence * *----------------------------* * This method is used to output an item list. ****************************************************************************/ HRESULT CTTSEngObj::OutputSentence( CItemList& ItemList, ISpTTSEngineSite* pOutputSite ) { HRESULT hr = S_OK; ULONG WordIndex; //--- Lookup words in our voice SPLISTPOS ListPos = ItemList.GetHeadPosition(); while( ListPos && !(pOutputSite->GetActions() & SPVES_ABORT) ) { CSentItem& Item = ItemList.GetNext( ListPos ); //--- Process sentence items switch( Item.pXmlState->eAction ) { //--- Speak some text --------------------------------------- case SPVA_Speak: { //--- We don't say anything for punctuation or control characters // in this sample. if( iswalpha( Item.pItem[0] ) || iswdigit( Item.pItem[0] ) ) { //--- Lookup the word, if we can't find it just use the first one for( WordIndex = 0; WordIndex < m_ulNumWords; ++WordIndex ) { if( ( m_pWordList[WordIndex].ulTextLen == Item.ulItemLen ) && ( !wcsnicmp( m_pWordList[WordIndex].pText, Item.pItem, Item.ulItemLen )) ) { break; } } if( WordIndex == m_ulNumWords ) { WordIndex = 0; } //--- Queue the event CSpEvent Event; Event.eEventId = SPEI_WORD_BOUNDARY; Event.elParamType = SPET_LPARAM_IS_UNDEFINED; Event.ullAudioStreamOffset = m_ullAudioOff; Event.lParam = Item.ulItemSrcOffset; Event.wParam = Item.ulItemSrcLen; hr = pOutputSite->AddEvents( &Event, 1 ); //--- Queue the audio data hr = pOutputSite->Write( m_pWordList[WordIndex].pAudio, m_pWordList[WordIndex].ulNumAudioBytes, NULL ); //--- Update the audio offset m_ullAudioOff += m_pWordList[WordIndex].ulNumAudioBytes; } } break; //--- Output some silence for a pause ----------------------- case SPVA_Silence: { BYTE Buff[1000]; memset( Buff, 0, 1000 ); ULONG NumSilenceBytes = Item.pXmlState->SilenceMSecs * 22; //--- Queue the audio data in chunks so that we can get // interrupted if necessary. while( !(pOutputSite->GetActions() & SPVES_ABORT) ) { if( NumSilenceBytes > 1000 ) { hr = pOutputSite->Write( Buff, 1000, NULL ); NumSilenceBytes -= 1000; } else { hr = pOutputSite->Write( Buff, NumSilenceBytes, NULL ); break; } } //--- Update the audio offset m_ullAudioOff += NumSilenceBytes; } break; //--- Fire a bookmark event --------------------------------- case SPVA_Bookmark: { //--- The bookmark is NOT a null terminated string in the Item, but we need //--- to convert it to one. Allocate enough space for the string. WCHAR * pszBookmark = (WCHAR *)_alloca((Item.ulItemLen + 1) * sizeof(WCHAR)); memcpy(pszBookmark, Item.pItem, Item.ulItemLen * sizeof(WCHAR)); pszBookmark[Item.ulItemLen] = 0; //--- Queue the event SPEVENT Event; Event.eEventId = SPEI_TTS_BOOKMARK; Event.elParamType = SPET_LPARAM_IS_STRING; Event.ullAudioStreamOffset = m_ullAudioOff; Event.lParam = (LPARAM)pszBookmark; Event.wParam = _wtol(pszBookmark); hr = pOutputSite->AddEvents( &Event, 1 ); } break; case SPVA_Pronounce: //--- Our sample engine doesn't handle this. If it // did, you would use the associated pronunciation in // the XmlState structure instead of the lexicon. break; case SPVA_ParseUnknownTag: //--- This will reference an XML tag that is unknown to SAPI // if your engine has private tags to control state, you // would examine these tags and see if you recognize it. This // would also be the point that you would make the rendering // state change. break; } } return hr; } /* CTTSEngObj::OutputSentence */
/***************************************************************************** * CTTSEngObj::Speak * *-------------------* * Description: * This is the primary method that SAPI calls to render text. *----------------------------------------------------------------------------- * Input Parameters * * pUser * Pointer to the current user profile object. This object contains * information like what languages are being used and this object * also gives access to resources like the SAPI master lexicon object. * * dwSpeakFlags * This is a set of flags used to control the behavior of the * SAPI voice object and the associated engine. * * VoiceFmtIndex * Zero based index specifying the output format that should * be used during rendering. * * pTextFragList * A linked list of text fragments to be rendered. There is * one fragement per XML state change. If the input text does * not contain any XML markup, there will only be a single fragment. * * pOutputSite * The interface back to SAPI where all output audio samples and events are written. * * Return Values * S_OK - This should be returned after successful rendering or if * rendering was interrupted because *pfContinue changed to FALSE. * E_INVALIDARG * E_OUTOFMEMORY * *****************************************************************************/ STDMETHODIMP CTTSEngObj::Speak( DWORD dwSpeakFlags, REFGUID rguidFormatId, const WAVEFORMATEX * pWaveFormatEx, const SPVTEXTFRAG* pTextFragList, ISpTTSEngineSite* pOutputSite ) { SPDBG_FUNC( "CTTSEngObj::Speak" ); HRESULT hr = S_OK; //--- Check args if( SP_IS_BAD_INTERFACE_PTR( pOutputSite ) || SP_IS_BAD_READ_PTR( pTextFragList ) ) { hr = E_INVALIDARG; } else { //--- Init some vars m_pCurrFrag = pTextFragList; m_pNextChar = m_pCurrFrag->pTextStart; m_pEndChar = m_pNextChar + m_pCurrFrag->ulTextLen; m_ullAudioOff = 0; //--- Parse // We've supplied a simple word/sentence breaker just to show one // way of walking the fragment list. It obviously doesn't deal with // things like abreviations and expansion of numbers and dates. CItemList ItemList; while( SUCCEEDED( hr ) && !(pOutputSite->GetActions() & SPVES_ABORT) ) { //--- Do skip? if( pOutputSite->GetActions() & SPVES_SKIP ) { long lSkipCnt; SPVSKIPTYPE eType; hr = pOutputSite->GetSkipInfo( &eType, &lSkipCnt ); if( SUCCEEDED( hr ) ) { //--- Notify SAPI how many items we skipped. We're returning zero // because this feature isn't implemented. hr = pOutputSite->CompleteSkip( 0 ); } } //--- Build the text item list if( SUCCEEDED( hr ) && (hr = GetNextSentence( ItemList )) != S_OK ) { break; } //--- We aren't going to do any part of speech determination, // prosody, or pronunciation determination. If you were, one thing // you will need is access to the SAPI lexicon. You can get that with // the following call. // CComPtr<ISpLexicon> cpLexicon; // hr = pUser->GetLexicon( &cpLexicon ); if( !(pOutputSite->GetActions() & SPVES_ABORT) ) { //--- Fire begin sentence event CSentItem& FirstItem = ItemList.GetHead(); CSentItem& LastItem = ItemList.GetTail(); CSpEvent Event; Event.eEventId = SPEI_SENTENCE_BOUNDARY; Event.elParamType = SPET_LPARAM_IS_UNDEFINED; Event.ullAudioStreamOffset = m_ullAudioOff; Event.lParam = (LPARAM)FirstItem.ulItemSrcOffset; Event.wParam = (WPARAM)LastItem.ulItemSrcOffset + LastItem.ulItemSrcLen - FirstItem.ulItemSrcOffset; hr = pOutputSite->AddEvents( &Event, 1 ); //--- Output if( SUCCEEDED( hr ) ) { hr = OutputSentence( ItemList, pOutputSite ); } } } //--- S_FALSE just says that we hit the end, return okay if( hr == S_FALSE ) { hr = S_OK; } } return hr; } /* CTTSEngObj::Speak */
void AbstractMidiEditor::songChanged(int type)/*{{{*/ { if (type) { if (type & (SC_PART_REMOVED | SC_PART_MODIFIED | SC_PART_INSERTED | SC_TRACK_REMOVED)) { genPartlist(); // close window if editor has no parts anymore if (parts()->empty()) { close(); return; } } if (canvas) canvas->songChanged(type); if (type & (SC_PART_REMOVED | SC_PART_MODIFIED | SC_PART_INSERTED | SC_TRACK_REMOVED)) { updateHScrollRange(); if (canvas) setWindowTitle(canvas->getCaption()); if (type & SC_SIG) time->update(); } if (type & SC_SELECTION) { CItemList list = canvas->getSelectedItemsForCurrentPart(); //Get the rightmost selected note (if any) iCItem i, iRightmost; CItem* rightmost = NULL; i = list.begin(); while (i != list.end()) { if (i->second->isSelected()) { iRightmost = i; rightmost = i->second; } ++i; } if (rightmost) { int pos = rightmost->pos().x(); pos = canvas->mapx(pos) + hscroll->offset(); int s = hscroll->offset(); int e = s + canvas->width(); if (pos > e) hscroll->setOffset(rightmost->pos().x()); if (pos < s) hscroll->setOffset(rightmost->pos().x()); } } } }/*}}}*/
void CGroupOfGenerators::AddItems (SItemAddCtx &Ctx) // AddItems // // Add items { int i, j; // If we need to adjust counts, then do a separate algorithm if (SetsAverageValue()) { // Get the count adjustment. Metric rCountAdj = GetCountAdj(Ctx.iLevel); Metric rLoops = floor(rCountAdj); Metric rLastLoopAdj = rCountAdj - rLoops; // Loop if we have extra items int iFullLoops = (int)rLoops; for (i = 0; i < iFullLoops + 1; i++) { // For a full loop we just add the items if (i < iFullLoops) AddItemsInt(Ctx); // Otherwise we need to add partial items else { // Add the items to a private list. CItemList LocalList; CItemListManipulator ItemList(LocalList); SItemAddCtx LocalCtx(ItemList); LocalCtx.iLevel = Ctx.iLevel; AddItemsInt(LocalCtx); // Now loop over the items and adjust the count appropriately. for (j = 0; j < LocalList.GetCount(); j++) { const CItem &Item = LocalList.GetItem(j); int iOriginalCount = Item.GetCount(); // Adjust the count Metric rNewCount = iOriginalCount * rLastLoopAdj; Metric rNewCountInt = floor(rNewCount); int iNewCount = (int)rNewCountInt; Metric rExtra = rNewCount - rNewCountInt; int iExtraChance = (int)(100000.0 * rExtra); if (mathRandom(0, 100000) < iExtraChance) iNewCount++; // Add the item with the new count if (iNewCount > 0) { if (iNewCount == iOriginalCount) Ctx.ItemList.AddItem(Item); else { CItem NewItem(Item); NewItem.SetCount(iNewCount); Ctx.ItemList.AddItem(NewItem); } } } } } } else AddItemsInt(Ctx); }