史上最难乐器——“滑速奏音”
来源:互联网 发布:网络用语泥塑什么意思 编辑:程序博客网 时间: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: };#endifPlayLayer.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
- 史上最难乐器——“滑速奏音”
- 分享教程 之FL Studio创建音乐—添加乐器
- 乐器租赁
- 成人乐器与少儿乐器教学区别
- 演奏乐器总结(待续...)
- 古乐器欣赏
- MIDI乐器编号
- 乐器数字接口 MIDI
- 音乐家演奏乐器
- 关于孔乐器
- 乐器的研究
- 乐器、音乐与声学
- 乐器的分类
- 【乐器常识】声音之美
- html5实现乐器的播放效果
- midiOutShortMsg 函数的用法以及乐器编号
- 学习乐器的好处(1)
- 乐器的音色与交响乐的欣赏
- HDU 2085 核反应堆
- HDU 2086 A1 = ?
- hadoop之单机模式与伪分布式模式部署
- 贤内助——ICMP协议
- Mac 上通过U盘安装Windows 7
- 史上最难乐器——“滑速奏音”
- HDU 2087 剪花布条
- HDU 2088 Box of Bricks
- HDU 2089 不要62
- ibatis和Hibernate的比较浅析
- HDU 2090 算菜价
- 学习node-webkit
- Codeforces 279B Books
- 傻瓜安装 Cacti for Windows