#include "Song.h" #include "Music.h" #include "TimbreResource.h" #include "Scale.h" #include "resourceManager.h" #include "usageDatabase.h" #include "uniqueID.h" #include "imageCache.h" #include "packSaver.h" #include "minorGems/util/stringUtils.h" #include "minorGems/util/log/AppLog.h" // static inits Song *Song::sBlankSong = NULL; void Song::staticInit() { sBlankSong = new Song(); // save once sBlankSong->finishEdit(); } void Song::staticFree() { delete sBlankSong; } void Song::setupDefault() { const char *defaultName = "default"; memcpy( mName, defaultName, strlen( defaultName ) + 1 ); uniqueID blankID = Music::sBlankMusic->getUniqueID(); int x; int y; for( y=0; ygetUniqueID(); for( x=0; xgetUniqueID(); // normal, default mSpeed = 1; makeUniqueID(); } Song::Song() { setupDefault(); } // song loaded from file Song::Song( uniqueID inID ) : mID( inID ) { int length; char fromNetwork; unsigned char *data = loadResourceData( "song", mID, &length, &fromNetwork ); if( data != NULL ) { // save this one initFromData( data, length, fromNetwork, true ); delete [] data; data = NULL; } else { setupDefault(); } } Song::Song( uniqueID inID, unsigned char *inData, int inLength, char inFromNetwork, char inSaveWholeSong ) : mID( inID ) { initFromData( inData, inLength, inFromNetwork, inSaveWholeSong ); } void Song::initFromData( unsigned char *inData, int inLength, char inFromNetwork, char inSaveWholeSong ) { readFromBytes( inData, inLength ); if( inFromNetwork ) { // phrases might not be present locally, either // more efficient to load them in a chunk instead of with separate // messages uniqueID ids[SI*S]; int i=0; for( int ty=0; ty 10 ) { AppLog::getLog()->logPrintf( Log::ERROR_LEVEL, "Error: Song name %s is too long (10 max)\n", inName ); } else { memcpy( mName, inName, newLength + 1 ); } } uniqueID Song::getPhrase( int inX, int inY ) { return mPhrases[inY][inX]; } int Song::getRowLength( int inY ) { return mRowLengths[inY]; } int Song::getRowLoudness( int inY ) { return mRowLoudness[inY]; } int Song::getRowStereo( int inY ) { return mRowStereo[inY]; } uniqueID Song::getTimbre( int inY ) { return mTimbres[inY]; } uniqueID Song::getScale() { return mScale; } int Song::getSpeed() { return mSpeed; } char *Song::getSongName() { return stringDuplicate( mName ); } // finishes the edit, generates a new unique ID, saves result void Song::finishEdit( char inGenerateNewID ) { uniqueID oldID = mID; if( inGenerateNewID ) { makeUniqueID(); } if( !equal( oldID, mID ) || ! resourceExists( "song", mID ) ) { // change int numBytes; unsigned char *bytes = makeBytes( &numBytes ); saveResourceData( "song", mID, mName, bytes, numBytes ); delete [] bytes; // track usages addUsage( mID, mScale ); for( int y=0; ygetChannel( 0 ), fullImage->getChannel( 1 ), fullImage->getChannel( 2 ) }; for( int py=0; pygetChannel( 0 ), tImage->getChannel( 1 ), tImage->getChannel( 2 ), tImage->getChannel( 3 ) }; // compute average of all non-trans phrase pixels for( int c=0; c<3; c++ ) { // sum first int numNonTrans = 0; for( int i=0; i 0 ) { fullC[c][fullP] += tC[c][i]; numNonTrans ++; } } if( numNonTrans > 0 ) { fullC[c][fullP] /= numNonTrans; fullC[c][fullP] *= (timbreColor)[c]; } else { fullC[c][fullP] = 0; } } delete tImage; } } return fullImage; } Sprite *Song::getSprite( char inUseTrans, char inCacheOK ) { // ignore inUseTrans Image *cachedImage = NULL; if( inCacheOK ) { cachedImage = getCachedImage( mID, false ); } if( cachedImage == NULL ) { cachedImage = getImage(); if( inCacheOK ) { addCachedImage( mID, false, cachedImage ); } } Sprite *sprite = new Sprite( cachedImage ); if( !inCacheOK ) { // image not in cache... we must destroy it delete cachedImage; } return sprite; } const char *Song::getResourceType() { return "song"; } Song Song::getDefaultResource() { return *sBlankSong; } #include "minorGems/util/SimpleVector.h" unsigned char *Song::makeBytes( int *outLength ) { SimpleVector buffer; int y, x; for( y=0; y= SI ) { memcpy( (void *)mRowLengths, inBytes, SI ); inBytes = &( inBytes[ SI ] ); inLength -= SI; } success = readUniqueIDs( (uniqueID *)mTimbres, SI, inBytes, inLength, &numBytesUsed ); if( success ) { inBytes = &( inBytes[ numBytesUsed ] ); inLength -= numBytesUsed; } if( inLength >= SI ) { memcpy( (void *)mRowLoudness, inBytes, SI ); inBytes = &( inBytes[ SI ] ); inLength -= SI; } if( inLength >= SI ) { memcpy( (void *)mRowStereo, inBytes, SI ); inBytes = &( inBytes[ SI ] ); inLength -= SI; } mScale = readUniqueID( inBytes, inLength, &numBytesUsed ); if( numBytesUsed == U ) { inBytes = &( inBytes[ numBytesUsed ] ); inLength -= numBytesUsed; } if( inLength > 0 ) { mSpeed = inBytes[0]; inBytes = &( inBytes[ 1 ] ); inLength -= 1; } // remainder is name if( inLength <= 11 ) { memcpy( mName, inBytes, inLength ); } } void Song::makeUniqueID() { int numBytes; unsigned char *bytes = makeBytes( &numBytes ); mID = ::makeUniqueID( bytes, numBytes ); delete [] bytes; } #include "musicPlayer.h" extern char noteToggles[PARTS][S][N][N]; extern int partLengths[PARTS]; extern double partLoudness[PARTS]; extern double partStereo[PARTS]; void Song::setInPlayer( Song inOldSong, Song inNewSong, char inForceUpdate ) { // timbre updates are slow... only do the ones we need uniqueID oldTimbres[SI]; for( int y=0; y x ) { for( int py=0; py