史上最难乐器——“滑速奏音”

来源:互联网 发布:网络用语泥塑什么意思 编辑:程序博客网 时间:2024/06/09 16:57

昨天(2014年7月25日)深夜想到的点子,用触摸屏检测手指滑动的速度,然后根据该速度决定播放的音符音调高低。

这种音乐演奏方式闻所未闻,显然是音乐史上又一次革命。

用cocos2d-x 2.20作为游戏引擎,代码不多。核心是触摸屏检测、SimpleAudioEngine音效和英文加速字符显示的CCLabelAtlas的使用。

以下为主要源码

PlayLayer.h

#ifndef __PLAYLAYER_H__#define __PLAYLAYER_H__#include "cocos2d.h"USING_NS_CC;class PlayLayer:public CCLayer{public:    PlayLayer();    ~PlayLayer();    CREATE_FUNC(PlayLayer);    virtual bool init();    void menuCloseCallback(CCObject* pSender);// a selector callback    static cocos2d::CCScene* scene();    virtual void registerWithTouchDispatcher();    virtual void ccTouchesBegan(CCSet* touches, CCEvent* event);    virtual void ccTouchesMoved(CCSet* touches, CCEvent* event);    virtual void ccTouchesEnded(CCSet* touches, CCEvent* event);    virtual void ccTouchesCancelled(CCSet* touches, CCEvent* event);    CCSize visibleSize;    CCPoint origin;    //CCLabelTTF *finger[11];    CCLabelAtlas *finger[11];#define MULTI_TOUCH_COUNT_MAX 11    CCPoint firstClickDownPos[MULTI_TOUCH_COUNT_MAX];    CCPoint preClickDownPos[MULTI_TOUCH_COUNT_MAX];    bool selectedClickDown[MULTI_TOUCH_COUNT_MAX];    struct cc_timeval firstFingerTime[MULTI_TOUCH_COUNT_MAX];    struct cc_timeval preFingerTime[MULTI_TOUCH_COUNT_MAX];    int preTones[MULTI_TOUCH_COUNT_MAX];    float tonesSum[MULTI_TOUCH_COUNT_MAX];    int tonesIndex[MULTI_TOUCH_COUNT_MAX];private:    };#endif
PlayLayer.c

#include "SSIDebug.h"#include "PlayLayer.h"#include "SimpleAudioEngine.h"#include "math.h"USING_NS_CC;using namespace CocosDenshion;PlayLayer::PlayLayer(){    CCLog("Win32:[%s,%s,%d]:",__FILE__,__FUNCTION__,__LINE__);}PlayLayer::~PlayLayer(){}CCScene* PlayLayer::scene(){    // 'scene' is an autorelease object    CCScene *scene = CCScene::create();    // 'layer' is an autorelease object    PlayLayer *layer = PlayLayer::create();    // add layer as a child to scene    scene->addChild(layer);    // return the scene    return scene;}bool PlayLayer::init(){    int i, j;    char ch[30];    SSIDebug("enter\n");    setTouchEnabled(true);    setPositionX(0);    visibleSize = CCDirector::sharedDirector()->getVisibleSize();    origin = CCDirector::sharedDirector()->getVisibleOrigin();    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(        "CloseNormal.png",        "CloseSelected.png",        this,        menu_selector(PlayLayer::menuCloseCallback));    pCloseItem->setPosition(ccp(origin.x +/* visibleSize.width -*/ pCloseItem->getContentSize().width/2 ,        origin.y - pCloseItem->getContentSize().height/2 + visibleSize.height));    CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);    pMenu->setPosition(CCPointZero);    this->addChild(pMenu, 1);    for(i = 3; i <=4; i++)    {        for(j = 1; j <= 12; j++)        {            sprintf(ch,"Piano88s_ogg/%d/%d.ogg", i, j);            CCLOG("preload:%s",ch);            SimpleAudioEngine::sharedEngine()->preloadEffect( ch );        }    }    SimpleAudioEngine::sharedEngine()->setEffectsVolume(0.5);    /*    sprintf(ch,"Piano88s_ogg/%d/%d.ogg", i, j);    CCLOG("play:%s",ch);    CCLOG("play=%d",SimpleAudioEngine::sharedEngine()->playEffect(ch));    */    for (int i = 0;i < MULTI_TOUCH_COUNT_MAX;i++)    {        sprintf(ch,"Finger[%d]", i);        //finger[i] = CCLabelTTF::create(ch, "Arial", 24, CCSizeZero, kCCTextAlignmentLeft, kCCVerticalTextAlignmentTop);        finger[i] = CCLabelAtlas::create(ch, "fonts/tuffy_bold_italic-charmap.plist");        finger[i]->setPosition(ccp(0/*origin.x  + finger[i]->getContentSize().width/2*/,            origin.y + visibleSize.height - finger[i]->getContentSize().height*(i+2)));        this->addChild(finger[i], 1);    }    SSIDebug("reaturn\n");    return true;}void PlayLayer::menuCloseCallback(CCObject* pSender){#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)    CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");#else    CCDirector::sharedDirector()->end();#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)    exit(0);#endif#endif}void PlayLayer::registerWithTouchDispatcher(){    CCDirector* pDirector = CCDirector::sharedDirector();    pDirector->getTouchDispatcher()->addStandardDelegate(this, 0);}void PlayLayer::ccTouchesBegan(CCSet* touches, CCEvent* event){    int i = 0,iTouchID;    CCSprite *pSprite;    char str[200];    void **pMBInfo;    CCSetIterator iter = touches->begin();    for (; iter != touches->end(); iter++, i++)    {        CCTouch* pTouch = (CCTouch*)(*iter);        CCPoint location = pTouch->getLocationInView();        location = CCDirector::sharedDirector()->convertToGL(location);        iTouchID = pTouch->getID();        SSIDebug2("[%d]beg(%f,%f)\t",pTouch->getID(),location.x,location.y);        if (CCTime::gettimeofdayCocos2d(&(firstFingerTime[iTouchID]), NULL) != 0)        {            SSIDebug("error in gettimeofda\n");        }        else        {            preFingerTime[iTouchID].tv_sec = firstFingerTime[iTouchID].tv_sec;            preFingerTime[iTouchID].tv_usec = firstFingerTime[iTouchID].tv_usec;        }        firstClickDownPos[iTouchID].setPoint(location.x, location.y);        preClickDownPos[iTouchID].setPoint(location.x, location.y);        preTones[iTouchID] = -1;        tonesSum[iTouchID] = 0;        tonesIndex[iTouchID] = 0;        sprintf(str,"Finger[%d]=(%4.0f,%4.0f) v=%09.2f", iTouchID,location.x, location.y,0);        finger[iTouchID]->setString(str);        selectedClickDown[pTouch->getID()] = true;    }    SSIDebug("ccTouchesBegan return\n");}void PlayLayer::ccTouchesMoved(CCSet* touches, CCEvent* event){    int i,j,iTouchType,iTouchID,tone;    char str[200];    struct cc_timeval now;    float deltaT;    CCSetIterator iter = touches->begin();    SSIDebug2("touches->count()=%d\n",touches->count());    for (i = 0; iter != touches->end(); iter++, i++)    {        CCTouch* pTouch = (CCTouch*)(*iter);        CCPoint location = pTouch->getLocationInView();        location = CCDirector::sharedDirector()->convertToGL(location);        iTouchID = pTouch->getID();        SSIDebug2("[%d]mov(%f,%f)\t",pTouch->getID(),location.x,location.y);        if (selectedClickDown[iTouchID] == true)        {            selectedClickDown[iTouchID] = false;        }        preClickDownPos[iTouchID].setPoint(location.x, location.y);        if (CCTime::gettimeofdayCocos2d(&now, NULL) != 0)        {            SSIDebug("error in gettimeofda\n");        }        else        {            deltaT = (now.tv_sec - preFingerTime[iTouchID].tv_sec)                + (now.tv_usec - preFingerTime[iTouchID].tv_usec) / 1000000.0f;            deltaT = MAX(0, deltaT);            preFingerTime[iTouchID].tv_sec = now.tv_sec;            preFingerTime[iTouchID].tv_usec = now.tv_usec;            //tone = logf(pTouch->getDelta().getLength()/deltaT);            tonesSum[iTouchID] += logf(pTouch->getDelta().getLength()/deltaT);            if(tonesIndex[iTouchID] < 5)            {            tonesIndex[iTouchID]++;            }            else            {            tone = tonesSum[iTouchID]/tonesIndex[iTouchID];            if(preTones[iTouchID] != tone)            {__android_log_print(ANDROID_LOG_ERROR,"SSI-so",\"file:%s function:%s line:%d %d",\__FILE__, __FUNCTION__, __LINE__, tone);if(tone>24) tone=24;if(tone<0) tone=0;if(tone>0 && tone<13){sprintf(str,"Piano88s_ogg/%d/%d.ogg", 3, tone);SimpleAudioEngine::sharedEngine()->playEffect(str);}else{sprintf(str,"Piano88s_ogg/%d/%d.ogg", 4, tone-12);SimpleAudioEngine::sharedEngine()->playEffect(str);}preTones[iTouchID] = tone;            }            tonesIndex[iTouchID] = 0;            tonesSum[iTouchID] = 0;            }            sprintf(str,"Finger[%d]{%2d}p=(%4.0f,%4.0f) v=%09.2f deltaT=%4.3f,l=%4.3f",iTouchID,preTones[iTouchID],location.x, location.y,pTouch->getDelta().getLength()/deltaT,deltaT,pTouch->getDelta().getLength());finger[iTouchID]->setString(str);finger[iTouchID]->setPosition(ccp(origin.x /*+ finger[iTouchID]->getContentSize().width/2*/,origin.y + visibleSize.height - finger[iTouchID]->getContentSize().height*(iTouchID+2)));        }    }    SSIDebug("ccTouchesMoved return\n");}void PlayLayer::ccTouchesEnded(CCSet* touches, CCEvent* event){    int i, iTouchID;    CCSetIterator iter = touches->begin();    SSIDebug2("touches->count()=%d\n",touches->count());    for (i = 0; iter != touches->end(); iter++,i++)    {        CCTouch* pTouch = (CCTouch*)(*iter);        CCPoint location = pTouch->getLocationInView();        location = CCDirector::sharedDirector()->convertToGL(location);        iTouchID = pTouch->getID();        SSIDebug2("[%d]end(%.1f,%.1f)\n",pTouch->getID(),location.x,location.y);        selectedClickDown[iTouchID] = false;    }    SSIDebug("ccTouchesEnded return\n");}void PlayLayer::ccTouchesCancelled(CCSet* touches, CCEvent* event){    CCSetIterator iter = touches->begin();    SSIDebug2("touches->count()=%d\n",touches->count());    for (; iter != touches->end(); iter++)    {        CCTouch* pTouch = (CCTouch*)(*iter);        CCPoint location = pTouch->getLocationInView();        location = CCDirector::sharedDirector()->convertToGL(location);        SSIDebug2("cancell(%f,%f)\t",location.x,location.y);    }    SSIDebug("\n");}
界面做得很简陋,黑屏加调试信息,显示每个手指的音符号、坐标、速度等等。

测试结果:连do rui mi fa so la si都很难滑出来,关键是滑速很难稳定,结果只能发出大量噪声。

如果有人能用这个软件弹出一首完整的歌曲,我只能说这简直要超神了!

唉,乐器的又一次革命就此胎死腹中了,先驱们的艰难我又体会到了。

本文中涉及源码为博主Krysl所有,禁止一切商业行为,仅供个人试验娱乐所用,禁止他人以可执行文件的形式传播,任何于2014年7月25日后盗用该点子的软硬件发行、专利注册等涉及商业的行为请接受道德的谴责 。转载请保留本段信息,原文网址:http://blog.csdn.net/krysl/article/details/38148927




0 0