bool DoubleDiagonalShoot::hasNext(int squareNumberWidth, int squareNumberHeight, int shipSize) { switch (shipSize) { case 4: if(shootedSquares4->contains(makeId(squareNumberWidth, squareNumberHeight))) return true; break; case 3: if (shootedSquares3->contains(makeId(squareNumberWidth, squareNumberHeight))) return true; break; case 2: if(shootedSquares2->contains(makeId(squareNumberWidth, squareNumberHeight))) return true; break; } int size = squareSize(squareNumberWidth, squareNumberHeight, shipSize); int x = squareNumberWidth * shipSize; int y = squareNumberHeight * shipSize; for (int i = 0; i < size/2; i++) { id = y * 10 + x; if (enemyField->attackable(id)) return false; x++; y++; } x = squareNumberWidth * shipSize; y = squareNumberHeight * shipSize; if (size < 3) { if (size != 1) { x++; y++; } id = y * 10 + x; if (enemyField->attackable(id)) return false; } else { x = squareNumberWidth * shipSize + size - 1; y = squareNumberHeight * shipSize + size - 2; id = y * 10 + x; if (enemyField->attackable(id)) return false; x--; y++; id = y * 10 + x; if (enemyField->attackable(id)) return false; } int sqr = makeId(squareNumberWidth, squareNumberHeight); return true; }
void tst_QOrganizerCollection::idStringFunctions() { // TODO: review test QOrganizerCollectionId id1(makeId("a", 1)); QOrganizerCollectionId id2(makeId("a", 1)); QOrganizerCollectionId id3(makeId("b", 1)); QOrganizerCollectionId id4(makeId("a", 2)); QVERIFY(qHash(id1) == qHash(id2)); QVERIFY(qHash(id1) != qHash(id4)); // note that the toString and fromString functions are // engine and id specific. This test merely checks that // the API is hooked up correctly. QVERIFY(id1.toString() == id2.toString()); QVERIFY(id1.toString() != id3.toString()); QVERIFY(id1.toString() != id4.toString()); QVERIFY(id3.toString() != id4.toString()); // this should "work" -- string of the correct format QString prebuiltidstring = QString("qtorganizer") + QString(":") + QString("a") + QString("::") + QString::number(2); QOrganizerCollectionId rebuiltid = QOrganizerCollectionId::fromString(prebuiltidstring); // QVERIFY(rebuiltid == id4); // -- this requires a working backend. // this string has the right format and one parameter, but requires a working backend prebuiltidstring = QString("qtorganizer") + QString(":") + QString("a") + QString(":") + QString("key=value") + QString(":") + QString::number(2); rebuiltid = QOrganizerCollectionId::fromString(prebuiltidstring); // QVERIFY(rebuiltid == id4); // -- this requires a working backend. // this string has the right format and some parameters, but requires a working backend prebuiltidstring = QString("qtorganizer") + QString(":") + QString("a") + QString(":") + QString("key=value&key2=value2") + QString(":") + QString::number(2); rebuiltid = QOrganizerCollectionId::fromString(prebuiltidstring); // QVERIFY(rebuiltid == id4); // -- this requires a working backend. // this string has the right format but misses the value for a parameter prebuiltidstring = QString("qtorganizer") + QString(":") + QString("a") + QString(":") + QString("key=value&key2=") + QString(":") + QString::number(2); rebuiltid = QOrganizerCollectionId::fromString(prebuiltidstring); // QVERIFY(rebuiltid == id4); // -- this requires a working backend. // this string misses a field (the parameters) prebuiltidstring = QString("qtorganizer") + QString(":") + QString("a") + QString(":") + QString::number(2); rebuiltid = QOrganizerCollectionId::fromString(prebuiltidstring); QVERIFY(rebuiltid == QOrganizerCollectionId()); // invalid so should be null. // this string misses two fields (params plus manager uri) prebuiltidstring = QString("qtorganizer") + QString(":") + QString::number(2); rebuiltid = QOrganizerCollectionId::fromString(prebuiltidstring); QVERIFY(rebuiltid == QOrganizerCollectionId()); // invalid so should be null. // this string misses the prefix (qtorganizer) prebuiltidstring = QString("notorganizer") + QString(":") + QString("a") + QString("::") + QString::number(2); rebuiltid = QOrganizerCollectionId::fromString(prebuiltidstring); QVERIFY(rebuiltid == QOrganizerCollectionId()); // invalid so should be null. // this string misses the manager uri prebuiltidstring = QString("notorganizer") + QString(":::") + QString::number(2); rebuiltid = QOrganizerCollectionId::fromString(prebuiltidstring); QVERIFY(rebuiltid == QOrganizerCollectionId()); // invalid so should be null. }
int DoubleDiagonalShoot::nextCell(int squareNumberWidth, int squareNumberHeight, int shipSize) { int size = squareSize(squareNumberWidth, squareNumberHeight, shipSize); int x = squareNumberWidth * shipSize; int y = squareNumberHeight * shipSize; for (int i = 0; i < size/2; i++) { id = y * 10 + x; if (enemyField->attackable(id)) return id; x++; y++; } x = squareNumberWidth * shipSize; y = squareNumberHeight * shipSize; if (size < 3) { if (size > 1) { x++; y++; } id = y * 10 + x; if (enemyField->attackable(id)) return id; } else { x = squareNumberWidth * shipSize + size - 1; y = squareNumberHeight * shipSize + size - 2; id = y * 10 + x; if (enemyField->attackable(id)) return id; x--; y++; id = y * 10 + x; if (enemyField->attackable(id)) return id; } int sqr = makeId(squareNumberWidth, squareNumberHeight); switch (shipSize) { case 4: shootedSquares4->append(makeId(squareNumberWidth, squareNumberHeight)); break; case 3: shootedSquares3->append(makeId(squareNumberWidth, squareNumberHeight)); break; case 2: shootedSquares2->append(makeId(squareNumberWidth, squareNumberHeight)); break; } return true; }
QModelIndex PackageModel::index( int row, int column, const QModelIndex &parent ) const { if (!parent.isValid()) // root { if ( row > rootItems.count() ) return QModelIndex(); unsigned int internalId = makeId( row, 0, INVALID_PARENT ); return createIndex( row, 0, internalId ); } else { unsigned int parentId = getRow( parent.internalId() ); return createIndex( row, column, makeId( row, column, parentId )); } }
void SipPresenceMonitor::getState(const Url& aor, UtlString& status) { UtlString contact; aor.getUserId(contact); contact += mHostAndPort; // Make the contact be a proper URI by prepending "sip:". contact.prepend("sip:"); UtlContainable* foundValue; mLock.acquire(); foundValue = mPresenceEventList.findValue(&contact); if (foundValue) { SipPresenceEvent* presenceEvent = dynamic_cast <SipPresenceEvent *> (foundValue); UtlString id; makeId(id, contact); presenceEvent->getTuple(id)->getStatus(status); OsSysLog::add(FAC_SIP, PRI_ERR, "SipPresenceMonitor::getState contact %s state = %s", contact.data(), status.data()); } else { OsSysLog::add(FAC_SIP, PRI_ERR, "SipPresenceMonitor::getState contact %s does not exist", contact.data()); status = STATUS_CLOSED; } mLock.release(); }
bool Flp::isValid(std::string filename) { std::fstream in(filename.c_str(),std::fstream::in|std::fstream::binary); if (! in.good()) return false; // check for the magic "FLhd" at the beginning int realMagic = makeId('F', 'L', 'h', 'd'); int magic = read32LE(in); if (realMagic != magic) return false; // header should be 6 bytes long const int header_len = read32LE(in); if (header_len != 6) return false; // some type thing const int type = read16LE(in); if (type != 0) return false; return true; }
// Caller must hold mLock. void SipPresenceMonitor::notifyStateChange(UtlString& contact, SipPresenceEvent* presenceEvent) { // Loop through the notifier list UtlHashMapIterator iterator(mStateChangeNotifiers); UtlString* listUri; StateChangeNotifier* notifier; Url contactUrl(contact); while ((listUri = dynamic_cast <UtlString *> (iterator()))) { notifier = dynamic_cast <StateChangeNotifier *> (mStateChangeNotifiers.findValue(listUri)); UtlString id; makeId(id, contact); Tuple* tuple = presenceEvent->getTuple(id); if (tuple) { UtlString status; tuple->getStatus(status); notifier->setStatus(contactUrl, status.compareTo(STATUS_CLOSED) == 0 ? StateChangeNotifier::AWAY : StateChangeNotifier::PRESENT); } else { notifier->setStatus(contactUrl, StateChangeNotifier::AWAY); } } }
Resource::Resource() : externalid { "" }, id {""} { id = makeId(); }
void tst_QOrganizerCollection::idHash() { // TODO: review tests QOrganizerCollectionId id1(makeId(QString(), 1)); QOrganizerCollectionId id2(makeId(QString(), 1)); QOrganizerCollectionId id3(makeId(QString(), 2)); QOrganizerCollectionId id4(makeId("a", 1)); QVERIFY(qHash(id1) == qHash(id2)); QVERIFY(qHash(id1) != qHash(id3)); // note that the hash function is dependent on the id type // in BasicCollectionLocalId, the hash function ignores the managerUri. QSet<QOrganizerCollectionId> set; set.insert(id1); set.insert(id2); set.insert(id3); set.insert(id4); QCOMPARE(set.size(), 3); }
void Sound::playVoice(int16_t objKey, uint32_t crc) { char name[16]; snprintf(name, sizeof(name), "%08X.WAV", crc); int dataSize; FILE *fp = fileOpen(name, &dataSize, kFileType_VOICE, false); debug(kDebug_SOUND, "Sound::playVoice() '%s' dataSize %d", name, dataSize); if (fp) { _mix.playWav(fp, dataSize, kDefaultVolume, kDefaultPan, makeId(objKey)); fileClose(fp); } }
std::vector<frts::TickablePtr> frts::Application::findTickables(const std::vector<std::string>& moduleNames) { std::vector<TickablePtr> result; for(const auto& moduleName : moduleNames) { auto id = makeId(moduleName); auto module = std::dynamic_pointer_cast<Tickable>(pluginManager.findModule(id)); result.push_back(module); } return result; }
void tst_QOrganizerCollection::idLessThan() { // TODO: review tests QOrganizerCollectionId id1(makeId("a", 1)); QOrganizerCollectionId id2(makeId("a", 1)); QVERIFY(!(id1 < id2)); QVERIFY(!(id2 < id1)); QVERIFY(id1 == id2); QOrganizerCollectionId id3(makeId("a", 2)); QOrganizerCollectionId id4(makeId("b", 1)); QOrganizerCollectionId id5(makeId(QString(), 2)); QVERIFY(id1 < id3); QVERIFY(!(id3 < id1)); QVERIFY(id1 < id4); QVERIFY(!(id4 < id1)); QVERIFY(id3 < id4); QVERIFY(!(id4 < id3)); QVERIFY(id5 < id1); QVERIFY(!(id1 < id5)); }
bool SipPresenceMonitor::addExtension(UtlString& groupName, Url& contactUrl) { bool result = false; mLock.acquire(); // Check whether the group has already existed. If not, create one. SipResourceList* list = dynamic_cast <SipResourceList *> (mMonitoredLists.findValue(&groupName)); if (list == NULL) { UtlString* listName = new UtlString(groupName); list = new SipResourceList((UtlBoolean)TRUE, listName->data(), PRESENCE_EVENT_TYPE); mMonitoredLists.insertKeyAndValue(listName, list); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPresenceMonitor::addExtension insert listName %s and object %p to the resource list", groupName.data(), list); } // Check whether the contact has already been added to the group UtlString resourceId; contactUrl.getIdentity(resourceId); Resource* resource = list->getResource(resourceId); if (resource == NULL) { resource = new Resource(resourceId); UtlString userName; contactUrl.getDisplayName(userName); resource->setName(userName); UtlString id; makeId(id, resourceId); resource->setInstance(id, STATE_PENDING); list->insertResource(resource); result = true; } else { OsSysLog::add(FAC_LOG, PRI_WARNING, "SipPresenceMonitor::addExtension contact %s already exists.", resourceId.data()); } int dummy; list->buildBody(&dummy); mLock.release(); return result; }
bool DoubleDiagonalShoot::twoSquareShooted(int squareNumberWidth, int squareNumberHeight) { int shipSize = 2; int id = makeId(squareNumberWidth, squareNumberHeight); if (shootedSquares2->contains(id)) { return true; } int x = squareNumberWidth * shipSize; int y = squareNumberHeight * shipSize; int squaresize = squareSize(squareNumberWidth, squareNumberWidth, shipSize); for(int i = 0; i < squaresize; i++) { id = y * 10 + x; //cout << id; if (enemyField->attackable(id)) return false; x++; y++; } shootedSquares2->append(makeId(squareNumberWidth, squareNumberHeight)); return true; }
/*! \internal \reimp Calculate and return an index for the parent of \a index. */ QModelIndex PackageModel::parent( const QModelIndex &index ) const { if (!index.isValid()) return QModelIndex(); int thisId = index.internalId(); unsigned int thisParent = getParent( thisId ); if ( thisParent == INVALID_PARENT ) { return QModelIndex(); } unsigned int internalId = makeId( thisParent, 0, INVALID_PARENT ); return createIndex( thisParent, 0, internalId ); }
bool DiagonalShoot::hasNext(int squareNumberWidth, int squareNumberHeight, int shipSize) { int id = makeId(squareNumberWidth, squareNumberHeight); switch (shipSize) { case 4: if(shootedSquares4->contains(makeId(squareNumberWidth, squareNumberHeight))) return true; break; case 3: if (shootedSquares3->contains(makeId(squareNumberWidth, squareNumberHeight))) return true; break; case 2: if(shootedSquares2->contains(makeId(squareNumberWidth, squareNumberHeight))) return true; break; } int x = squareNumberWidth * shipSize; int y = squareNumberHeight * shipSize; int squaresize = squareSize(squareNumberWidth, squareNumberWidth, shipSize); for(int i = 0; i < squaresize; i++) { id = y * 10 + x; //cout << id; if (enemyField->attackable(id)) return false; x++; y++; } switch (shipSize) { case 4: shootedSquares4->append(makeId(squareNumberWidth, squareNumberHeight)); break; case 3: shootedSquares3->append(makeId(squareNumberWidth, squareNumberHeight)); break; case 2: shootedSquares2->append(makeId(squareNumberWidth, squareNumberHeight)); break; } return true; }
// Returns TRUE if the requested state is different from the current state. bool SipPresenceMonitor::setStatus(const Url& aor, const Status value) { if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG)) { UtlString aorString; aor.toString(aorString); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPresenceMonitor::setStatus aor = '%s', value = %d %s", aorString.data(), value, (value == StateChangeNotifier::PRESENT ? "PRESENT" : value == StateChangeNotifier::AWAY ? "AWAY" : "UNKNOWN")); } bool result = false; UtlString contact; aor.getUserId(contact); contact += mHostAndPort; // Make the contact be a proper URI by prepending "sip:". contact.prepend("sip:"); // Create a presence event package and store it in the publisher SipPresenceEvent* sipPresenceEvent = new SipPresenceEvent(contact); UtlString id; makeId(id, contact); Tuple* tuple = new Tuple(id.data()); tuple->setStatus(value == StateChangeNotifier::PRESENT ? STATUS_OPEN : STATUS_CLOSED); tuple->setContact(contact, 1.0); sipPresenceEvent->insertTuple(tuple); // Add the SipPresenceEvent object to the presence event list. result = addPresenceEvent(contact, sipPresenceEvent); return result; }
void Sound::playSfx(int16_t objKey, int16_t sndKey) { if (sndKey != -1) { const uint32_t id = makeId(objKey, sndKey); if (_mix.isWavPlaying(id)) { // already playing return; } const uint8_t *p_sndtype = _res->getData(kResType_SND, sndKey, "SNDTYPE"); assert(p_sndtype && READ_LE_UINT32(p_sndtype) == 16); const uint8_t *p_sndinfo = _res->getData(kResType_SND, sndKey, "SNDINFO"); const DigiSnd *dc = findDigiSndByName((const char *)p_sndinfo); if (dc) { debug(kDebug_SOUND, "Sound::playSfx() '%s' offset 0x%X", (const char *)p_sndinfo, dc->offset); fileSetPos(_fpSnd, dc->offset, kFilePosition_SET); _mix.playWav(_fpSnd, dc->size, _sfxVolume, _sfxPan, id, _digiCompressed); } } _sfxVolume = kDefaultVolume; _sfxPan = kDefaultPan; }
void tst_QOrganizerCollection::hash() { // TODO: review tests QOrganizerCollectionId id(makeId("a", 1)); QOrganizerCollection c1; c1.setId(id); c1.setMetaData("key", "value"); QOrganizerCollection c2; c2.setId(id); c2.setMetaData("key", "value"); QOrganizerCollection c3; c3.setId(id); c3.setMetaData("key", "another value"); QOrganizerCollection c4; // no details c4.setId(id); QOrganizerCollection c5; c5.setId(id); c5.setMetaData("key", "value"); QVERIFY(qHash(c1) == qHash(c2)); QVERIFY(qHash(c1) != qHash(c3)); QVERIFY(qHash(c1) != qHash(c4)); QVERIFY(qHash(c1) == qHash(c5)); }
void Sound::stopSfx(int16_t objKey, int16_t sndKey) { _mix.stopWav(makeId(objKey, sndKey)); }
// Returns TRUE if the requested state is different from the current state. bool SipPresenceMonitor::addPresenceEvent(UtlString& contact, SipPresenceEvent* presenceEvent) { mLock.acquire(); bool requiredPublish = false; if (mPresenceEventList.find(&contact) == NULL) { requiredPublish = true; OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPresenceMonitor::addPresenceEvent adding presenceEvent %p for contact %s", presenceEvent, contact.data()); } else { OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPresenceMonitor::addPresenceEvent presenceEvent %p for contact %s already exists, updating its contents.", presenceEvent, contact.data()); // Get the object from the presence event list UtlContainable* oldKey; UtlContainable* foundValue; foundValue = mPresenceEventList.findValue(&contact); SipPresenceEvent* oldPresenceEvent = dynamic_cast <SipPresenceEvent *> (foundValue); UtlString oldStatus, status; UtlString id; makeId(id, contact); oldPresenceEvent->getTuple(id)->getStatus(oldStatus); presenceEvent->getTuple(id)->getStatus(status); if (status.compareTo(oldStatus) != 0) { requiredPublish = true; // Since we will be saving a new value, remove the old one. oldKey = mPresenceEventList.removeKeyAndValue(&contact, foundValue); delete oldKey; if (oldPresenceEvent) { delete oldPresenceEvent; } } } if (requiredPublish) { // Insert it into the presence event list. presenceEvent->buildBody(); mPresenceEventList.insertKeyAndValue(new UtlString(contact), presenceEvent); if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG)) { UtlString b; ssize_t l; presenceEvent->getBytes(&b, &l); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPresenceMonitor::addPresenceEvent presenceEvent %p for contact '%s' body '%s' is different from previous presenceEvent", presenceEvent, contact.data(), b.data()); } if (mToBePublished) { // Publish the content to the resource list. publishContent(contact, presenceEvent); } // Notify the state change. notifyStateChange(contact, presenceEvent); if (!mPersistentFile.isNull()) { // Start the save timer. mPersistenceTimer.oneshotAfter(sPersistInterval); } } else { // Since this presenceEvent will not be published (it does not // change the state we've sent out), delete it now. delete presenceEvent; } mLock.release(); return requiredPublish; }
// Write the presence events to the persistent file. void SipPresenceMonitor::writePersistentFile() { mLock.acquire(); // Create an empty document TiXmlDocument document; // Create a hard coded standalone declaration section document.Parse("<?xml version=\"1.0\" standalone=\"yes\"?>"); // Create the root node container TiXmlElement itemsElement ("items"); itemsElement.SetAttribute("type", sType.data()); itemsElement.SetAttribute("xmlns", sXmlNamespace.data()); int timeNow = (int)OsDateTime::getSecsSinceEpoch(); itemsElement.SetAttribute("timestamp", timeNow); // mPresenceEventList is a hash map that maps contacts to SipPresenceEvents. // SipPresenceEvents are hash maps of contacts to Tuples. In practice, // a SipPresenceEvent has only one Tuple. (And if it had more, there // would be no way to discover what they are, as there is no iterator.) // Tuples are triples: id, contact, status. // Loop through all the events in mPresenceEventList. UtlHashMapIterator iterator(mPresenceEventList); UtlString* contact; while ((contact = dynamic_cast <UtlString*> (iterator()))) { // Create an item container TiXmlElement itemElement ("item"); // Get the SipPresenceEvent. SipPresenceEvent* event = dynamic_cast <SipPresenceEvent*> (iterator.value()); // Calculate the id of the Tuple. UtlString id; makeId(id, *contact); // Get the Tuple. Tuple* tuple = event->getTuple(id); // Get the status. UtlString status; tuple->getStatus(status); // Construct the <item>. TiXmlElement id_element("id"); TiXmlText id_content(id); id_element.InsertEndChild(id_content); itemElement.InsertEndChild(id_element); TiXmlElement contact_element("contact"); TiXmlText contact_content(contact->data()); contact_element.InsertEndChild(contact_content); itemElement.InsertEndChild(contact_element); TiXmlElement status_element("status"); TiXmlText status_content(status); status_element.InsertEndChild(status_content); itemElement.InsertEndChild(status_element); // Add the <item> element to the <items> element. itemsElement.InsertEndChild ( itemElement ); } // Attach <items> to the root node to the document document.InsertEndChild(itemsElement); document.SaveFile(mPersistentFile); mLock.release(); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPresenceMonitorPersistenceTask::writePersistentFile file written"); }
void SipPresenceMonitor::publishContent(UtlString& contact, SipPresenceEvent* presenceEvent) { #ifdef SUPPORT_RESOURCE_LIST // Loop through all the resource lists UtlHashMapIterator iterator(mMonitoredLists); UtlString* listUri; SipResourceList* list; Resource* resource; UtlString id, state; while (listUri = dynamic_cast <UtlString *> (iterator())) { bool contentChanged = false; list = dynamic_cast <SipResourceList *> (mMonitoredLists.findValue(listUri)); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPresenceMonitor::publishContent listUri %s list %p", listUri->data(), list); // Search for the contact in this list resource = list->getResource(contact); if (resource) { resource->getInstance(id, state); if (presenceEvent->isEmpty()) { resource->setInstance(id, STATE_TERMINATED); } else { UtlString id; makeId(id, contact); Tuple* tuple = presenceEvent->getTuple(id); UtlString status; tuple->getStatus(status); if (status.compareTo(STATUS_CLOSED) == 0) { resource->setInstance(id, STATE_TERMINATED); } else { resource->setInstance(id, STATE_ACTIVE); } } list->buildBody(); contentChanged = true; } if (contentChanged) { // Publish the content to the subscribe server // Make a copy, because mpSipPublishContentMgr will own it. HttpBody* pHttpBody = new HttpBody(*(HttpBody*)list); mSipPublishContentMgr.publish(listUri->data(), PRESENCE_EVENT_TYPE, PRESENCE_EVENT_TYPE, 1, &pHttpBody); } } #endif // Publish the content to the subscribe server // Make a copy, because mpSipPublishContentMgr will own it. HttpBody* pHttpBody = new HttpBody(*(HttpBody*)presenceEvent); mSipPublishContentMgr.publish(contact.data(), PRESENCE_EVENT_TYPE, PRESENCE_EVENT_TYPE, 1, &pHttpBody); }
Flp::Flp(std::string filename) : m_good(false), m_debug(false) { m_file.open(filename.c_str(),std::fstream::in|std::fstream::binary); if (! m_file.good()) { m_errMsg = "Error opening the file."; return; } // check for the magic "FLhd" at the beginning int realMagic = makeId('F', 'L', 'h', 'd'); int magic = read32LE(); if (realMagic != magic) { m_errMsg = "Doesn't look like an .flp file."; return; } // header should be 6 bytes long const int header_len = read32LE(); if (header_len != 6) { m_errMsg = "File format is too different from what we know" " (header should be 6 bytes long, but is " + Utils::intToString(header_len) + ")."; return; } // some type thing const int type = read16LE(); if (type != 0) { m_errMsg = "type " + Utils::intToString(type) + " is not supported."; return; } // number of channels m_project.numChannels = read16LE(); if (m_project.numChannels < 1 || m_project.numChannels > 1000) { m_errMsg = "invalid number of channels: " + Utils::intToString(m_project.numChannels) + "."; return; } // ppq const int ppq = read16LE(); if (ppq < 0) { m_errMsg = "invalid ppq: " + Utils::intToString(ppq) + "."; return; } // search for FLdt chunk bool valid = false; while (true) { int id = read32LE(); const int len = read32LE(); if (m_file.eof()) { m_errMsg = "Unexpected end of file."; return; } // sanity check if (len < 0 || len >= 0x10000000) { m_errMsg = "Invalid chunk length: " + Utils::intToString(len) + "."; return; } // check for FLdt if (id == makeId('F', 'L', 'd', 't')) { // TODO: read meta-information valid = true; break; } skip(len); } if (! valid) { m_errMsg = "Could not find FLdt chunk."; return; } // headers checked out ok. now read the events. for (int i=0; i<m_project.numChannels; ++i) { m_project.channels.push_back(FL_Channel()); } char * text = NULL; int text_len = 0; int cur_channel = -1; while (! m_file.eof()) { FLP_Events ev = static_cast<FLP_Events>(readByte()); int data = readByte(); // see FLP_Format for the juicy details of this disgusting file format. if (ev >= FLP_Word && ev < FLP_Text) data = data | (readByte() << 8); if (ev >= FLP_Int && ev < FLP_Text) { data = data | (readByte() << 16); data = data | (readByte() << 24); } if (ev >= FLP_Text) { text_len = data & 0x7F; unsigned char shift = 0; while (data & 0x80) { data = readByte(); text_len = text_len | ((data & 0x7F) << (shift+=7)); } delete[] text; text = new char[text_len+1]; m_file.read(text, text_len); assert(m_file.good()); text[text_len] = 0; // null byte of string } // TODO: name these variables better // puc = pointer to an unsigned char const unsigned char * puc = (const unsigned char*) text; // pi = pointer to an int const int * pi = (const int *) text; FL_Channel * cc = cur_channel >= 0 ? &m_project.channels[cur_channel] : NULL; switch (ev) { // BYTE EVENTS case FLP_Byte: if (m_debug) std::cerr << "undefined byte " << data << std::endl; break; case FLP_NoteOn: if (m_debug) std::cerr << "note on: " << data << std::endl; // data = pos how to handle? break; case FLP_Vol: if (m_debug) std::cerr << "vol " << data << std::endl; break; case FLP_Pan: if (m_debug) std::cerr << "pan " << data << std::endl; break; case FLP_LoopActive: if (m_debug) std::cerr << "active loop: " << data << std::endl; break; case FLP_ShowInfo: if (m_debug) std::cerr << "show info: " << data << std::endl; break; case FLP_Shuffle: if (m_debug) std::cerr << "shuffle: " << data << std::endl; break; case FLP_MainVol: m_project.mainVolume = data; break; case FLP_PatLength: if (m_debug) std::cerr << "pattern length: " << data << std::endl; break; case FLP_BlockLength: if (m_debug) std::cerr << "block length: " << data << std::endl; break; case FLP_UseLoopPoints: cc->sampleUseLoopPoints = true; break; case FLP_LoopType: if (m_debug) std::cerr << "loop type: " << data << std::endl; break; case FLP_ChanType: if (m_debug) std::cerr << "channel type: " << data << std::endl; if (cc) { switch (data) { case 0: cc->generatorName = "Sampler"; break; case 1: cc->generatorName = "TS 404"; break; case 2: cc->generatorName = "3x Osc"; break; case 3: cc->generatorName = "Layer"; break; default: break; } } break; case FLP_MixSliceNum: cc->fxChannel = data+1; break; case FLP_EffectChannelMuted: if( m_project.currentEffectChannel <= c_NumFLFxChannels ) { m_project.effectChannels[m_project.currentEffectChannel] .isMuted = ( data & 0x08 ) > 0 ? false : true; } break; // WORD EVENTS case FLP_NewChan: cur_channel = data; break; case FLP_NewPat: m_project.currentPattern = data - 1; if( m_project.currentPattern > m_project.maxPatterns ) m_project.maxPatterns = m_project.currentPattern; break; case FLP_Tempo: m_project.tempo = data; break; case FLP_CurrentPatNum: m_project.activeEditPattern = data; break; case FLP_FX: if (m_debug) std::cerr << "FX: " << data << std::endl; break; case FLP_Fade_Stereo: if( data & 0x02 ) { cc->sampleReversed = true; } else if( data & 0x100 ) { cc->sampleReverseStereo = true; } break; case FLP_CutOff: if (m_debug) std::cerr << "cutoff (sample): " << data << std::endl; break; case FLP_PreAmp: cc->sampleAmp = data; break; case FLP_Decay: if (m_debug) std::cerr << "decay (sample): " << data << std::endl; break; case FLP_Attack: if (m_debug) std::cerr << "attack (sample): " << data << std::endl; break; case FLP_MainPitch: m_project.mainPitch = data; break; case FLP_Resonance: if (m_debug) std::cerr << "resonance (sample): " << data << std::endl; break; case FLP_LoopBar: if (m_debug) std::cerr << "loop bar: " << data << std::endl; break; case FLP_StDel: if (m_debug) std::cerr << "stdel (delay?): " << data << std::endl; break; case FLP_FX3: if (m_debug) std::cerr << "FX 3: " << data << std::endl; break; case FLP_ShiftDelay: if (m_debug) std::cerr << "shift delay: " << data << std::endl; break; case FLP_Dot: cc->dots.push_back( ( data & 0xff ) + ( m_project.currentPattern << 8 ) ); break; case FLP_LayerChans: m_project.channels[data].layerParent = cur_channel; cc->generatorName = "Layer"; // DWORD EVENTS case FLP_Color: // TODO: double check that this works cc->color.r = (data & 0xFF000000) >> 24; cc->color.g = (data & 0x00FF0000) >> 16; cc->color.b = (data & 0x0000FF00) >> 8; break; case FLP_PlayListItem: { FL_PlayListItem i; i.position = (data & 0xffff) * 192; i.length = 192; i.pattern = (data >> 16) - 1; m_project.playListItems.push_back(i); if (i.pattern > m_project.maxPatterns) m_project.maxPatterns = i.pattern; break; } case FLP_FXSine: if (m_debug) std::cerr << "fx sine: " << data << std::endl; break; case FLP_CutCutBy: if (m_debug) std::cerr << "cut cut by: " << data << std::endl; break; case FLP_MiddleNote: cc->baseNote = data+9; break; case FLP_DelayReso: if (m_debug) std::cerr << "delay resonance: " << data << std::endl; break; case FLP_Reverb: if (m_debug) std::cerr << "reverb (sample): " << data << std::endl; break; case FLP_IntStretch: if (m_debug) std::cerr << "int stretch (sample): " << data << std::endl; break; // TEXT EVENTS case FLP_Text_ChanName: cc->name = text; break; case FLP_Text_PatName: m_project.patternNames[m_project.currentPattern] = text; break; case FLP_Text_CommentRTF: if (m_debug) std::cerr << "TODO: RTF text comment." << std::endl; /* TODO: support RTF comments { QByteArray ba( text, text_len ); QBuffer buf( &ba ); buf.open( QBuffer::ReadOnly ); lineno = 0; attr_clear_all(); op = html_init(); hash_init(); Word * word = word_read( &buf ); QString out; word_print( word, out ); word_free( word ); op_free( op ); p.projectNotes = out; outstring = ""; break; } */ case FLP_Text_Title: m_project.projectTitle = text; break; case FLP_Text_SampleFileName: cc->sampleFileName = text; cc->generatorName = "Sampler"; m_sampleSet.insert(cc->sampleFileName); break; case FLP_Text_Version: { if (m_debug) std::cerr << "FLP version: " << text << std::endl; m_project.versionString = text; // divide the version string into numbers std::vector<std::string> numbers; Utils::split(m_project.versionString, numbers, "."); m_project.version = (Utils::stringToInt(numbers[0]) << 8) + (Utils::stringToInt(numbers[1]) << 4 ) + (Utils::stringToInt(numbers[2]) << 0 ); if( m_project.version >= 0x600 ) m_project.versionSpecificFactor = 100; break; } case FLP_Text_PluginName: { std::string pluginName = text; // we add all plugins to effects list and then // remove the ones that aren't effects later. m_effectPlugins.insert(pluginName); cc->generatorName = pluginName; if (m_debug) std::cerr << "plugin: " << pluginName << std::endl; break; } case FLP_Text_EffectChanName: ++m_project.currentEffectChannel; if( m_project.currentEffectChannel <= c_NumFLFxChannels ) { m_project.effectChannels[m_project.currentEffectChannel] .name = text; } break; case FLP_Text_Delay: if (m_debug) std::cerr << "delay data: " << text << std::endl; // pi[1] seems to be volume or similiar and // needs to be divided // by m_project.versionSpecificFactor break; case FLP_Text_TS404Params: if( cc && cc->pluginSettings == NULL ) { cc->pluginSettings = new char[text_len]; std::memcpy( cc->pluginSettings, text, text_len ); cc->pluginSettingsLength = text_len; cc->generatorName = "TS 404"; } break; case FLP_Text_NewPlugin: // TODO: if it's an effect plugin make a new effect if (m_debug) { std::cerr << "new plugin: " << std::endl; dump_mem(text, text_len); } break; case FLP_Text_PluginParams: if( cc && cc->pluginSettings == NULL ) { cc->pluginSettings = new char[text_len]; memcpy(cc->pluginSettings, text, text_len); cc->pluginSettingsLength = text_len; } break; case FLP_Text_ChanParams: cc->arpDir = pi[10]; cc->arpRange = pi[11]; cc->selectedArp = pi[12]; if( cc->selectedArp < 8 ) { const int mappedArps[] = {0, 1, 5, 6, 2, 3, 4}; cc->selectedArp = mappedArps[cc->selectedArp]; } cc->arpTime = ( ( pi[13]+1 ) * m_project.tempo ) / ( 4*16 ) + 1; cc->arpGate = ( pi[14] * 100.0f ) / 48.0f; cc->arpEnabled = pi[10] > 0; break; case FLP_Text_EnvLfoParams: { const float scaling = 1.0 / 65536.0f; FL_Channel_Envelope e; switch (cc->envelopes.size()) { case 1: e.target = Volume; break; case 2: e.target = Cut; break; case 3: e.target = Resonance; break; default: e.target = NumTargets; break; } e.predelay = pi[2] * scaling; e.attack = pi[3] * scaling; e.hold = pi[4] * scaling; e.decay = pi[5] * scaling; e.sustain = 1-pi[6] / 128.0f; e.release = pi[7] * scaling; if (e.target == Volume) e.amount = pi[1] ? 1 : 0; else e.amount = pi[8] / 128.0f; cc->envelopes.push_back(e); break; } case FLP_Text_BasicChanParams: cc->volume = pi[1] / m_project.versionSpecificFactor; cc->panning = pi[0] / m_project.versionSpecificFactor; if (text_len > 12) { cc->filterType = puc[20]; cc->filterCut = puc[12]; cc->filterRes = puc[16]; cc->filterEnabled = (puc[13] == 0); if( puc[20] >= 6 ) cc->filterCut *= 0.5f; } break; case FLP_Text_OldFilterParams: cc->filterType = puc[8]; cc->filterCut = puc[0]; cc->filterRes = puc[4]; cc->filterEnabled = ( puc[1] == 0 ); if( puc[8] >= 6 ) cc->filterCut *= 0.5; break; case FLP_Text_AutomationData: { const int bpae = 12; const int imax = text_len / bpae; for (int i = 0; i < imax; ++i) { FL_Automation a; a.pos = pi[3*i+0] / (4*ppq / 192); a.value = pi[3*i+2]; a.channel = pi[3*i+1] >> 16; a.control = pi[3*i+1] & 0xffff; if (a.channel >= 0 && a.channel < m_project.numChannels) { m_project.channels[a.channel].automationData .push_back(a); } } break; } case FLP_Text_PatternNotes: { const int bpn = 20; const int imax = ( text_len + bpn - 1 ) / bpn; for (int i = 0; i < imax; ++i) { int ch = *( puc + i*bpn + 6 ); int pan = *( puc + i*bpn + 16 ); int vol = *( puc + i*bpn + 17 ); int pos = *( (int *)( puc + i*bpn ) ); int key = *( puc + i*bpn + 12 ); int len = *( (int*)( puc + i*bpn + 8 ) ); pos /= (4*ppq) / 192; len /= (4*ppq) / 192; note n( len, pos, key, vol, pan); if( ch < m_project.numChannels ) { m_project.channels[ch].notes.push_back( std::make_pair(m_project.currentPattern, n)); } else { if (m_debug) std::cerr << "Invalid ch: " << ch << std::endl; } } break; } case FLP_Text_ChanGroupName: if (m_debug) std::cerr << "channel group name: " << text << std::endl; break; case 225: { enum FLP_EffectParams { EffectParamVolume = 0x1fc0 }; const int bpi = 12; const int imax = text_len / bpi; for (int i = 0; i < imax; ++i) { const int param = pi[i*3+1] & 0xffff; const int ch = ( pi[i*3+1] >> 22 ) & 0x7f; if( ch < 0 || ch > c_NumFLFxChannels ) continue; const int val = pi[i*3+2]; if( param == EffectParamVolume ) { m_project.effectChannels[ch].volume = (val / m_project.versionSpecificFactor); } else { if (m_debug) { std::cerr << "FX-ch: " << ch << " param: " << param << " value: " << val << std::endl; } } } break; } case 233: // playlist items { const int bpi = 28; const int imax = text_len / bpi; for (int i = 0; i < imax; ++i) { const int pos = pi[i*bpi/sizeof(int)+0] / ((4*ppq) / 192); const int len = pi[i*bpi/sizeof(int)+2] / ((4*ppq) / 192); const int pat = pi[i*bpi/sizeof(int)+3] & 0xfff; // whatever these magic numbers are for... if( pat > 2146 && pat <= 2278 ) { FL_PlayListItem i; i.position = pos; i.length = len; i.pattern = 2278 - pat; m_project.playListItems.push_back(i); } else { if (m_debug) { std::cerr << "unknown playlist item: " << text << std::endl; } } } break; } default: if( ev >= FLP_Text ) { if (m_debug) { std::cerr << "unhandled text (ev: " << ev << ", len: " << text_len << "): " << text << std::endl; } } else { if (m_debug) { std::cerr << "handling of FLP-event " << ev << " not implemented yet (data=" << data << ")" << std::endl; } } break; } } // for each fruity wrapper, extract the plugin name. for (unsigned int i=0; i<m_project.channels.size(); ++i) tryFruityWrapper(&m_project.channels[i]); for (unsigned int i=0; i<m_project.effects.size(); ++i) tryFruityWrapper(&m_project.effects[i]); // create list of sample dependencies m_sampleStrings.clear(); std::set<std::string>::iterator it; for (it=m_sampleSet.begin(); it != m_sampleSet.end(); ++it) m_sampleStrings.push_back(*it); // effects are the ones that aren't channels. m_channelPlugins.clear(); m_effectStrings.clear(); for (unsigned int i=0; i<m_project.channels.size(); ++i) m_channelPlugins.insert(m_project.channels[i].generatorName); for (it=m_effectPlugins.begin(); it != m_effectPlugins.end(); ++it) { if (m_channelPlugins.count(*it) == 0) m_effectStrings.push_back(*it); } m_good = true; }
void Sound::stopVoice(int16_t objKey) { _mix.stopWav(makeId(objKey)); }
bool Sound::isVoicePlaying(int16_t objKey) const { return _mix.isWavPlaying(makeId(objKey)); }