int print_midstats(struct schedule *sched, struct stats *old_stats) { TIMERTYPE temptime; float timedif = 0; struct listed_entity *le = sched->br.busylist; struct stats tempstats; float total_mbits = 0; GETTIME(temptime); timedif = floatdiff(&temptime, &sched->lasttick); LOG("Time:\t%lu\n", GETSECONDS(temptime)); while (le != NULL) { struct scheduled_event *ev = (struct scheduled_event *)le->entity; if (ev->opt->get_stats != NULL) { memset(&tempstats, 0, sizeof(struct stats)); ev->opt->get_stats((void *)ev->opt, (void *)&tempstats); neg_stats(&tempstats, ev->stats); total_mbits = BYTES_TO_MBITSPS(tempstats.total_bytes); LOG("Event:\t%s\t", ev->opt->filename); LOG("Network:\t%5.0fMb/s\tDropped %lu\tIncomplete %lu", total_mbits / timedif, tempstats.dropped, tempstats.incomplete); if (tempstats.progress != -1) { LOG("\tProgress %02d%%", tempstats.progress); } LOG("\n"); add_stats(ev->stats, &tempstats); } le = le->child; } memset(&tempstats, 0, sizeof(struct stats)); oper_to_all(sched->default_opt->diskbranch, BRANCHOP_GETSTATS, (void *)&tempstats); neg_stats(&tempstats, old_stats); total_mbits = BYTES_TO_MBITSPS(tempstats.total_written); LOG("HD-Speed:\t%5.0fMb/s\n", total_mbits / timedif); add_stats(old_stats, &tempstats); LOG("Ringbuffers: "); print_br_stats(sched->default_opt->membranch); LOG("Recpoints: "); print_br_stats(sched->default_opt->diskbranch); COPYTIME(temptime, sched->lasttick); LOG("----------------------------------------\n"); return 0; }
int parse_options(int argc, char **argv, struct opt_s *opt) { int ret; while ((ret = getopt(argc, argv, "d:i:t:s:n:m:w:p:q:ur:a:vVI:A:W:xc:hf:")) != -1) { switch (ret) { case 'i': opt->address_to_bind_to = strdup(optarg); break; case 'c': opt->cfgfile = (char *)malloc(sizeof(char) * FILENAME_MAX); //CHECK_ERR_NONNULL(opt->cfgfile, "Cfgfile malloc"); LOG ("Path for cfgfile specified. All command line options before this argument might be ignored\n"); ret = read_full_cfg(opt); if (ret != 0) { E("Error parsing cfg file. Exiting"); free(opt->cfgfile); return -1; } break; case 'v': opt->optbits |= VERBOSE; break; case 'f': LOG("Logging to %s\n", optarg); fflush(file_out); file_out = fopen(optarg, "a"); if (!file_out) { E("Failed to open log file %s: %s", optarg, strerror(errno)); return -1; } file_err = file_out; break; case 'h': usage(argv[0]); return -1; break; case 'd': opt->n_drives = atoi(optarg); break; #if(DAEMON) case 'e': GETSECONDS(opt->starting_time) = atoi(optarg); break; #endif case 'I': opt->minmem = atoi(optarg); break; case 'x': opt->optbits |= USE_RX_RING; break; case 'W': opt->do_w_stuff_every = atoi(optarg) * MEG; break; case 'A': opt->maxmem = atoi(optarg); break; case 'V': opt->optbits |= MOUNTPOINT_VERBOSE; break; case 't': opt->optbits &= ~LOCKER_CAPTURE; if (!strcmp(optarg, "fanout")) { //opt->capture_type = CAPTURE_W_FANOUT; opt->optbits |= CAPTURE_W_FANOUT; } else if (!strcmp(optarg, "udpstream")) { //opt->capture_type = CAPTURE_W_UDPSTREAM; opt->optbits |= CAPTURE_W_UDPSTREAM; } /* else if (!strcmp(optarg, "sendfile")){ //opt->capture_type = CAPTURE_W_SPLICER; opt->optbits |= CAPTURE_W_SPLICER; } */ else if (!strcmp(optarg, "dummy")) { //opt->capture_type = CAPTURE_W_SPLICER; opt->optbits |= CAPTURE_W_DUMMY; } else { LOGERR("Unknown packet capture type [%s]\n", optarg); usage(argv[0]); return -1; } break; /* Fanout choosing removed and set to default LB since * Implementation not that feasible anyway case 'a': opt->optbits &= ~LOCKER_FANOUT; if (!strcmp(optarg, "hash")){ //opt->fanout_type = PACKET_FANOUT_HASH; opt->optbits |= PACKET_FANOUT_HASH; } else if (!strcmp(optarg, "lb")){ //opt->fanout_type = PACKET_FANOUT_LB; opt->optbits |= PACKET_FANOUT_LB; } else { LOGERR("Unknown fanout type [%s]\n", optarg); usage(argv[0]); exit(1); } break; */ case 'a': #ifdef HAVE_RATELIMITER //opt->optbits |= WAIT_BETWEEN; opt->wait_nanoseconds = atoi(optarg) * 1000; ZEROTIME(opt->wait_last_sent); #else LOGERR("STREAMER: Rate limiter not compiled\n"); #endif break; case 'r': opt->rate = atoi(optarg); break; case 's': opt->port = atoi(optarg); break; case 'p': opt->packet_size = atoi(optarg); break; case 'u': #if(HAVE_HUGEPAGES) opt->optbits |= USE_HUGEPAGE; #endif break; case 'n': /* Commandeering this option */ opt->hostname = (char *)malloc(sizeof(char) * IP_LENGTH); if (strcpy(opt->hostname, optarg) == NULL) { E("strcpy hostname"); return -1; } //opt->n_threads = atoi(optarg); break; case 'q': opt->optbits &= ~LOCKER_DATATYPE; if (!strcmp(optarg, "vdif")) { D("Datatype as VDIF"); opt->optbits |= DATATYPE_VDIF; } else if (!strcmp(optarg, "mark5b")) { D("Datatype as Mark5"); opt->optbits |= DATATYPE_MARK5B; } else if (!strcmp(optarg, "udpmon")) { D("Datatype as UDPMON"); opt->optbits |= DATATYPE_UDPMON; } else if (!strcmp(optarg, "none")) { D("Datatype as none"); opt->optbits |= DATATYPE_UNKNOWN; } else { E("Unknown datatype %s", optarg); opt->optbits |= DATATYPE_UNKNOWN; } break; case 'm': if (!strcmp(optarg, "r")) { opt->optbits &= ~READMODE; //opt->read = 0; } else if (!strcmp(optarg, "s")) { //opt->read = 1; opt->optbits |= READMODE; } else { LOGERR("Unknown mode type [%s]\n", optarg); usage(argv[0]); exit(1); } break; case 'w': opt->optbits &= ~LOCKER_REC; if (!strcmp(optarg, "def")) { /* opt->rec_type = REC_DEF; opt->async = 0; */ opt->optbits |= REC_DEF; opt->optbits &= ~ASYNC_WRITE; } #ifdef HAVE_LIBAIO else if (!strcmp(optarg, "aio")) { /* opt->rec_type = REC_AIO; opt->async = 1; */ opt->optbits |= REC_AIO | ASYNC_WRITE; } #endif else if (!strcmp(optarg, "splice")) { /* opt->rec_type = REC_SPLICER; opt->async = 0; */ opt->optbits |= REC_SPLICER; opt->optbits &= ~ASYNC_WRITE; } else if (!strcmp(optarg, "dummy")) { /* opt->rec_type = REC_DUMMY; opt->buf_type = WRITER_DUMMY; */ opt->optbits &= ~LOCKER_WRITER; opt->optbits |= REC_DUMMY | WRITER_DUMMY; opt->optbits &= ~ASYNC_WRITE; } else { LOGERR("Unknown mode type [%s]\n", optarg); usage(argv[0]); //exit(1); return -1; } break; default: usage(argv[0]); exit(1); } } #if(!DAEMON) if (argc - optind != 2) { usage(argv[0]); exit(1); } #endif argv += optind; //argc -=optind; /* TODO: Enable giving a custom cfg-file on invocation */ #if(!DAEMON) if (opt->cfgfile != NULL) { } #endif //DAEMON /* If we're using rx-ring, then set the packet size to +TPACKET_HDRLEN */ /* if(opt->optbits & USE_RX_RING) opt->packet_size += TPACKET_HDRLEN; */ /* If n_threads isn't set, set it to n_drives +2 */ /* Not used. Maxmem limits this instead */ /* if(opt->n_threads == 0) opt->n_threads = opt->n_drives +2; */ if (opt->optbits & GET_A_FILENAME_AS_ARG) { opt->filename = (char *)malloc(sizeof(char) * FILENAME_MAX); CHECK_ERR_NONNULL(opt->filename, "filename malloc"); if (strcpy(opt->filename, argv[0]) == NULL) { E("strcpy filename"); return -1; } //opt->filename = argv[0]; } //opt->points = (struct rec_point *)calloc(opt->n_drives, sizeof(struct rec_point)); #if(!DAEMON) if (opt->optbits & READMODE && !(opt->optbits & CAPTURE_W_DISK2FILE)) { opt->hostname = (char *)malloc(sizeof(char) * IP_LENGTH); if (strcpy(opt->hostname, argv[1]) == NULL) { E("strcpy hostname"); return -1; } //opt->hostname = argv[1]; } else opt->time = atoi(argv[1]); #endif struct rlimit rl; /* Query max size */ /* TODO: Doesn't work properly althought mem seems to be unlimited */ ret = getrlimit(RLIMIT_DATA, &rl); if (ret < 0) { LOGERR("Failed to get rlimit of memory\n"); exit(1); } #if(DEBUG_OUTPUT) LOG("STREAMER: Queried max mem size %ld \n", rl.rlim_cur); #endif /* Check for memory limit */ //unsigned long minmem = MIN_MEM_GIG*GIG; if (opt->minmem > rl.rlim_cur && rl.rlim_cur != RLIM_INFINITY) { #if(DEBUG_OUTPUT) LOG("STREAMER: Limiting memory to %lu\n", rl.rlim_cur); #endif opt->minmem = rl.rlim_cur; } return 0; }
int main(int argc, char **argv) #endif { int err = 0; pthread_t streamer_pthread; #if(DAEMON) struct opt_s *opt = (struct opt_s *)opti; D("Starting thread from daemon"); #else LOG("Running in non-daemon mode\n"); struct opt_s *opt = malloc(sizeof(struct opt_s)); CHECK_ERR_NONNULL(opt, "opt malloc"); LOG("STREAMER: Reading parameters\n"); clear_and_default(opt, 1); err = parse_options(argc, argv, opt); if (err != 0) STREAMER_ERROR_EXIT; err = init_branches(opt); CHECK_ERR("init branches"); err = init_recp(opt); CHECK_ERR("init recpoints"); #ifdef HAVE_LIBCONFIG_H err = init_cfg(opt); //TODO: cfg destruction if (err != 0) { E("Error in cfg init"); STREAMER_ERROR_EXIT; } #endif //HAVE_LIBCONFIG_H err = init_rbufs(opt); CHECK_ERR("init rbufs"); #endif //DAEMON /* Check and set cfgs at this point */ //return -1; /* If we're sending stuff, check all the diskbranch members for the files they have */ /* Also updates the fileholders list to point the owners of files to correct drives */ #ifdef HAVE_LIBCONFIG_H if (opt->optbits & READMODE) { oper_to_all(opt->diskbranch, BRANCHOP_CHECK_FILES, (void *)opt); LOG ("For recording %s: %lu files were found out of %lu total. file index shows %ld files\n", opt->filename, opt->cumul_found, opt->cumul, afi_get_n_files(opt->fi)); } #endif //HAVE_LIBCONFIG_H /* Handle hostname etc */ /* TODO: Whats the best way that accepts any format? */ err = prep_streamer(opt); if (err != 0) { STREAMER_ERROR_EXIT; } if (opt->optbits & READMODE) LOG("STREAMER: In main, starting sending thread \n"); else LOG("STREAMER: In main, starting receiver thread \n"); #ifdef HAVE_LRT /* TCP streams start counting from accept and others from here */ if (!(opt->optbits & (CAPTURE_W_TCPSPLICE | CAPTURE_W_TCPSTREAM))) GETTIME(opt->starting_time); set_status_for_opt(opt, STATUS_RUNNING); err = pthread_create(&streamer_pthread, NULL, opt->streamer_ent->start, (void *)opt->streamer_ent); if (err != 0) { printf("ERROR; return code from pthread_create() is %d\n", err); STREAMER_ERROR_EXIT; } /* Other thread spawned so we can minimize our priority */ minimize_priority(); #ifdef TUNE_AFFINITY /* Caused some weird ass bugs and crashes so not used anymore NEVER */ /* Put the capture on the first core */ CPU_SET(0, &(opt->cpuset)); err = pthread_setaffinity_np(streamer_pthread, sizeof(cpu_set_t), &cpuset); if (err != 0) { E("Error: setting affinity: %d", err); } CPU_ZERO(&cpuset); #endif #endif { /* READMODE shuts itself down so we just go to pthread_join */ /* Check also that last_packet is 0. Else the thread should shut itself */ /* down */ if (!(opt->optbits & READMODE) && opt->last_packet == 0 && !(opt-> optbits & (CAPTURE_W_TCPSPLICE | CAPTURE_W_TCPSTREAM | CAPTURE_W_MULTISTREAM))) { TIMERTYPE now; GETTIME(now); while ((GETSECONDS(now) <= (GETSECONDS(opt->starting_time) + (long)opt->time)) && get_status_from_opt(opt) == STATUS_RUNNING) { sleep(1); GETTIME(now); } shutdown_thread(opt); pthread_mutex_lock(&(opt->membranch->branchlock)); pthread_cond_broadcast(&(opt->membranch->busysignal)); pthread_mutex_unlock(&(opt->membranch->branchlock)); } } err = pthread_join(streamer_pthread, NULL); if (err < 0) { printf("ERROR; return code from pthread_join() is %d\n", err); } else D("Streamer thread exit OK"); LOG("STREAMER: Threads finished. Getting stats for %s\n", opt->filename); GETTIME(opt->endtime); LOG("Blocking until owned buffers are released\n"); block_until_free(opt->membranch, opt); #if(DAEMON) LOG("Buffers finished\n"); if (get_status_from_opt(opt) != STATUS_STOPPED) { E("Thread didnt finish nicely with STATUS_STOPPED"); set_status_for_opt(opt, STATUS_FINISHED); } else set_status_for_opt(opt, STATUS_FINISHED); #else close_streamer(opt); #endif #if(DAEMON) D("Streamer thread exiting for %s", opt->filename); pthread_exit(NULL); #else close_opts(opt); STREAMER_EXIT; #endif }
void Fretboard::Draw(float time, dBChart *pSong, int track) { MFCALLSTACKc; MFView_Push(); MFRect rect; MFView_GetViewport(&rect); float aspect = rect.width / rect.height; aspect = MFClamp(0.82f, aspect, 2.0f); MFView_SetAspectRatio(aspect); if(viewPoint == 0) { // incoming MFView_ConfigureProjection(MFDEGREES(65.0f)/aspect, 1.0f, 100.0f); // Setup the Camera in 3D space. MFMatrix cameraMatrix; MFVector start = MakeVector( 0, 8, 3 ); MFVector dir = MakeVector( 0, 5, -8 ); dir = (dir-start) * (1.0f/1.777777777f); cameraMatrix.LookAt(start + dir*aspect, MakeVector(0.0f, 0.0f, 5.0f)); MFView_SetCameraMatrix(cameraMatrix); } else if(viewPoint == 1) { // overhead MFView_ConfigureProjection(MFDEGREES(45.0f), 1.0f, 100.0f); /* float aspect = MFDisplay_GetNativeAspectRatio(); MFView_SetAspectRatio(aspect); MFRect projRect; projRect.y = 15; projRect.height = -30; projRect.x = -projRect.y * aspect; projRect.width = -projRect.height * aspect; MFView_SetOrtho(&projRect); */ // Setup the Camera in 3D space. MFMatrix cameraMatrix; cameraMatrix.LookAt(MakeVector(0, 30, 10), MakeVector(0, 0, 10), MakeVector(0, 0, 1)); MFView_SetCameraMatrix(cameraMatrix); } else if(viewPoint == 2) { // overhead MFView_ConfigureProjection(MFDEGREES(45.0f), 1.0f, 100.0f); /* float aspect = MFDisplay_GetNativeAspectRatio(); MFView_SetAspectRatio(aspect); MFRect projRect; projRect.y = 15; projRect.height = -30; projRect.x = -projRect.y * aspect; projRect.width = -projRect.height * aspect; MFView_SetOrtho(&projRect); */ // Setup the Camera in 3D space. MFMatrix cameraMatrix; cameraMatrix.LookAt(MakeVector(0, 20, 13), MakeVector(0, 0, 13), MakeVector(-1, 0, 0)); MFView_SetCameraMatrix(cameraMatrix); } MFView_SetProjection(); MFMaterial *pFB = pSong->pFretboard ? pSong->pFretboard : pFretboard; MFMaterial_SetMaterial(pFB); MFPrimitive(PT_TriStrip, 0); int start = -4; int end = 60; int fadeStart = end - 10; float fretboardRepeat = 15.0f; float fretboardWidth = 7.0f; float columnWidth = fretboardWidth / 5.0f; float ringBorder = 0.1f; // draw the fretboard... MFBegin(((end-start) / 4) * 2 + 2); MFSetColourV(MFVector::white); float halfFB = fretboardWidth*0.5f; float offset = time*scrollSpeed; float topTime = time + end/scrollSpeed; float bottomTime = time + start/scrollSpeed; int a; float textureOffset = fmodf(offset, fretboardRepeat); for(a=start; a<end; a+=4) { float z = (float)a; MFSetTexCoord1(1.0f, 1.0f - (z+textureOffset) / fretboardRepeat); MFSetPosition(halfFB, 0.0f, z); MFSetTexCoord1(0.0f, 1.0f - (z+textureOffset) / fretboardRepeat); MFSetPosition(-halfFB, 0.0f, z); } float z = (float)a; MFSetTexCoord1(1.0f, 1.0f - (z+textureOffset) / fretboardRepeat); MFSetPosition(halfFB, 0.0f, z); MFSetTexCoord1(0.0f, 1.0f - (z+textureOffset) / fretboardRepeat); MFSetPosition(-halfFB, 0.0f, z); MFEnd(); // draw the selection region MFMaterial_SetMaterial(pFrets); MFPrimitive(PT_TriStrip, 0); if(gEditor.selectStart != gEditor.selectEnd) { float selectStartTime = GETSECONDS(pSong->CalculateTimeOfTick(gEditor.selectStart)); float selectEndTime = GETSECONDS(pSong->CalculateTimeOfTick(gEditor.selectEnd)); if(selectStartTime < topTime && selectEndTime > bottomTime) { selectStartTime = (MFMax(bottomTime, selectStartTime) - time) * scrollSpeed; selectEndTime = (MFMin(topTime, selectEndTime) - time) * scrollSpeed; MFBegin(4); MFSetColour(1.0f, 0.0f, 0.0f, 0.5f); MFSetPosition(-halfFB, 0.0f, selectEndTime); MFSetPosition(halfFB, 0.0f, selectEndTime); MFSetPosition(-halfFB, 0.0f, selectStartTime); MFSetPosition(halfFB, 0.0f, selectStartTime); MFEnd(); } } // draw the fretboard edges and bar lines const float barWidth = 0.2f; MFMaterial_SetMaterial(pBar); MFPrimitive(PT_TriStrip, 0); MFBegin(4); MFSetColour(0.0f, 0.0f, 0.0f, 0.8f); MFSetTexCoord1(0,0); MFSetPosition(-halfFB, 0.0f, barWidth); MFSetTexCoord1(1,0); MFSetPosition(halfFB, 0.0f, barWidth); MFSetTexCoord1(0,1); MFSetPosition(-halfFB, 0.0f, -barWidth); MFSetTexCoord1(1,1); MFSetPosition(halfFB, 0.0f, -barWidth); MFEnd(); MFMaterial_SetMaterial(pEdge); MFPrimitive(PT_TriStrip, 0); MFBegin(34); MFSetColour(0.0f, 0.0f, 0.0f, 0.3f); for(int col=1; col<5; col++) { if(col > 1) MFSetPosition(-halfFB + columnWidth*(float)col - 0.02f, 0.0f, (float)end); MFSetTexCoord1(0,0); MFSetPosition(-halfFB + columnWidth*(float)col - 0.02f, 0.0f, (float)end); MFSetTexCoord1(1,0); MFSetPosition(-halfFB + columnWidth*(float)col + 0.02f, 0.0f, (float)end); MFSetTexCoord1(0,1); MFSetPosition(-halfFB + columnWidth*(float)col - 0.02f, 0.0f, (float)start); MFSetTexCoord1(1,1); MFSetPosition(-halfFB + columnWidth*(float)col + 0.02f, 0.0f, (float)start); MFSetPosition(-halfFB + columnWidth*(float)col + 0.02f, 0.0f, (float)start); } MFSetColourV(MFVector::white); MFSetPosition(-halfFB - 0.1f, 0.0f, (float)end); MFSetTexCoord1(0,0); MFSetPosition(-halfFB - 0.1f, 0.0f, (float)end); MFSetTexCoord1(1,0); MFSetPosition(-halfFB + 0.1f, 0.0f, (float)end); MFSetTexCoord1(0,1); MFSetPosition(-halfFB - 0.1f, 0.0f, (float)start); MFSetTexCoord1(1,1); MFSetPosition(-halfFB + 0.1f, 0.0f, (float)start); MFSetPosition(-halfFB + 0.1f, 0.0f, (float)start); MFSetPosition(halfFB - 0.1f, 0.0f, (float)end); MFSetTexCoord1(0,0); MFSetPosition(halfFB - 0.1f, 0.0f, (float)end); MFSetTexCoord1(1,0); MFSetPosition(halfFB + 0.1f, 0.0f, (float)end); MFSetTexCoord1(0,1); MFSetPosition(halfFB - 0.1f, 0.0f, (float)start); MFSetTexCoord1(1,1); MFSetPosition(halfFB + 0.1f, 0.0f, (float)start); MFEnd(); // draw the frets.... MFMaterial_SetMaterial(pBar); MFPrimitive(PT_TriStrip, 0); int bottomTick = pSong->CalculateTickAtTime((int64)(bottomTime*1000000.0f)); int res = pSong->GetRes(); int ticks = bHalfFrets ? res/2 : res; int fretBeat = bottomTick + ticks - 1; fretBeat -= fretBeat % ticks; float fretTime = GETSECONDS(pSong->CalculateTimeOfTick(fretBeat)); while(fretTime < topTime) { bool halfBeat = (fretBeat % res) != 0; bool bar = false; if(!halfBeat) { GHEvent *pLastTS = pSong->sync.GetMostRecentEvent(GHE_TimeSignature, fretBeat); if(pLastTS) bar = ((fretBeat - pLastTS->tick) % (pLastTS->parameter*res)) == 0; else if(fretBeat == 0) bar = true; } float bw = bar ? barWidth : barWidth*0.5f; MFBegin(4); float position = (fretTime - time) * scrollSpeed; if(!halfBeat) MFSetColourV(MFVector::white); else MFSetColourV(MakeVector(1,1,1,0.3f)); MFSetTexCoord1(0,0); MFSetPosition(-halfFB, 0.0f, position + bw); MFSetTexCoord1(1,0); MFSetPosition(halfFB, 0.0f, position + bw); MFSetTexCoord1(0,1); MFSetPosition(-halfFB, 0.0f, position + -bw); MFSetTexCoord1(1,1); MFSetPosition(halfFB, 0.0f, position + -bw); MFEnd(); fretBeat += ticks; fretTime = GETSECONDS(pSong->CalculateTimeOfTick(fretBeat)); } // draw the notes... GHEventManager ¬eStream = pSong->notes[track]; GHEvent *pEv = noteStream.First(); int64 topTimeus = (int64)(topTime*1000000.0f); while(pEv && pEv->time < topTimeus) { if((pEv->event == GHE_Note || pEv->event == GHE_Special) && pEv->tick + pEv->parameter >= bottomTick) { float evTime = GETSECONDS(pEv->time); // TODO: we need to calculate the end of the hold... float noteEnd = evTime; if(pEv->parameter) noteEnd = GETSECONDS(pSong->CalculateTimeOfTick(pEv->tick + pEv->parameter)); if(pEv->event == GHE_Note && pEv->played != 1) { // draw a note int key = pEv->key; bool tap = false; // check if there is a previous note, and it is in range if(pEv->Prev() && pEv->Prev()->tick < pEv->tick && pEv->Prev()->tick > pEv->tick - (res/2) && pEv->Prev()->key != pEv->key && (!pEv->Next() || !(pEv->Next()->tick == pEv->tick)) && !pEv->Prev()->parameter && !(pEv->Prev()->Prev() && pEv->Prev()->Prev()->tick == pEv->Prev()->tick)) { tap = true; } int noteX = gConfig.controls.leftyFlip[0] ? 4-key : key; float position = (GETSECONDS(pEv->time) - time)*scrollSpeed; float xoffset = -halfFB + columnWidth*0.5f + (float)noteX*columnWidth; if(pEv->parameter) { MFMaterial_SetMaterial(pFrets); float whammyTop = (noteEnd - time)*scrollSpeed; MFPrimitive(PT_TriStrip, 0); // TODO: we could consider not drawing this part of the hold line.. seems reasonable that it terminates at the line... if(gEditor.state == GHPS_Stopped) { if(position < 0.0f) { MFBegin(4); MFSetColourV(gColours[key]); MFSetPosition(xoffset - 0.2f, 0.0f, MFMin(whammyTop, 0.0f)); MFSetPosition(xoffset + 0.2f, 0.0f, MFMin(whammyTop, 0.0f)); MFSetPosition(xoffset - 0.2f, 0.0f, position); MFSetPosition(xoffset + 0.2f, 0.0f, position); MFEnd(); } } if(whammyTop > 0.0f) { // this half could have waves cruising down it if we wanted to support the whammy... MFBegin(4); MFSetColourV(gColours[key]); MFSetPosition(xoffset - 0.2f, 0.0f, MFMin(whammyTop, (float)end)); MFSetPosition(xoffset + 0.2f, 0.0f, MFMin(whammyTop, (float)end)); MFSetPosition(xoffset - 0.2f, 0.0f, MFMax(position, 0.0f)); MFSetPosition(xoffset + 0.2f, 0.0f, MFMax(position, 0.0f)); MFEnd(); } } if(evTime >= bottomTime) { MFMatrix mat; mat.SetScale(MakeVector(0.5f/20, 0.5f/20, 0.5f/20)); mat.Translate(MakeVector(xoffset, 0.03f, position)); MFModel_SetWorldMatrix(pButton, mat); MFStateBlock *pSB = MFStateBlock_CreateTemporary(64); MFStateBlock_SetVector(pSB, MFSCV_DiffuseColour, pEv->played == -1 ? MakeVector(0.3f, 0.3f, 0.3f, 1.0f) : MFVector::white); // MFStateBlock_SetVector(pSB, MFSCV_DiffuseColour, position < 0.0f ? MakeVector(0.3f, 0.3f, 0.3f, 1.0f) : MFVector::white); // MFRenderer_SetRenderStateOverride(MFRS_MaterialOverride, (uint32&)(tap ? pButtonMat[key] : pButtonRing[key])); MFRenderer_AddModel(pButton, pSB, MFView_GetViewState()); // render the note time if(bRenderNoteTimes) { MFView_Push(); MFView_SetOrtho(&rect); MFVector pos; MFView_TransformPoint3DTo2D(MakeVector(xoffset, 0.0f, position), &pos); pos.x += 16.0f; pos.y -= 26.0f; int minutes = (int)(pEv->time / 60000000); int seconds = (int)((pEv->time % 60000000) / 1000000); int milliseconds = (int)((pEv->time % 1000000) / 1000); MFFont_DrawTextf(pText, pos, 20.0f, MFVector::yellow, "%s: %d:%02d.%d\nTick: %g", MFTranslation_GetString(pStrings, TRACK_TIME), minutes, seconds, milliseconds, (float)pEv->tick/res); MFView_Pop(); } } } if(pEv->event == GHE_Special) { // static MFVector specialColours[3] = { MakeVector(1,0,0,1), MakeVector(1,1,0,1), MakeVector(0,0,1,1) }; // static float specialX[3] = { halfFB + 0.2f, halfFB + 1, -halfFB - 1 }; // static float specialWidth[3] = { 0.8f, 0.8f, 0.8f }; static MFVector specialColours[3] = { MakeVector(1,0,0,0.5f), MakeVector(1,1,0,0.5f), MakeVector(0,0,1,0.5f) }; static float specialX[3] = { -halfFB, halfFB - 0.8f, -halfFB }; static float specialWidth[3] = { 0.8f, 0.8f, fretboardWidth }; float bottom = (evTime - time)*scrollSpeed; float top = (noteEnd - time)*scrollSpeed; int key = pEv->key; MFMaterial_SetMaterial(pFrets); MFPrimitive(PT_TriStrip, 0); MFBegin(4); MFSetColourV(specialColours[key]); MFSetPosition(specialX[key], 0.0f, MFMin(top, (float)end)); MFSetPosition(specialX[key]+specialWidth[key], 0.0f, MFMin(top, (float)end)); MFSetPosition(specialX[key], 0.0f, MFMax(bottom, (float)start)); MFSetPosition(specialX[key]+specialWidth[key], 0.0f, MFMax(bottom, (float)start)); MFEnd(); } } pEv = pEv->Next(); } // MFRenderer_SetRenderStateOverride(MFRS_MaterialOverride, NULL); // draw circles at the bottom.. MFMaterial_SetMaterial(pRing); for(int a=0; a<5; a++) { DrawRing(-halfFB + (float)a*columnWidth + columnWidth*ringBorder, 0.0f, columnWidth*(1.0f-ringBorder*2)); } for(int a=0; a<5; a++) { dBControlType keys_righty[] = { dBCtrl_Edit_Note0, dBCtrl_Edit_Note1, dBCtrl_Edit_Note2, dBCtrl_Edit_Note3, dBCtrl_Edit_Note4 }; dBControlType keys_lefty[] = { dBCtrl_Edit_Note4, dBCtrl_Edit_Note3, dBCtrl_Edit_Note2, dBCtrl_Edit_Note1, dBCtrl_Edit_Note0 }; dBControlType *keys = gConfig.controls.leftyFlip[0] ? keys_lefty : keys_righty; int ringPos = gConfig.controls.leftyFlip[0] ? 4-a : a; MFMaterial_SetMaterial(pColourRing[a]); DrawRing(-halfFB + (float)ringPos*columnWidth, 0.0f, columnWidth, !TestControl(keys[a], GHCT_Hold)); } // render trigger particles MFParticleSystem_Draw(pParticles); // render text and stuff MFView_SetOrtho(&rect); pEv = pSong->sync.GetNextEvent(bottomTick); while(pEv && pEv->time < topTimeus) { float evTime = GETSECONDS(pEv->time); if(evTime > bottomTime) { if(pEv->event == GHE_BPM) { float position = (evTime - time) * scrollSpeed; MFVector pos; MFView_TransformPoint3DTo2D(MakeVector(halfFB + 0.2f, 0.0f, position), &pos); pos.y -= 12.0f; MFFont_DrawTextf(pText, pos, 24.0f, MakeVector(0,0.5f,0,1), "%s: %g", MFTranslation_GetString(pStrings, TRACK_BPM), (float)pEv->parameter * 0.001f); } if(pEv->event == GHE_Anchor) { int minutes = (int)(pEv->time / 60000000); int seconds = (int)((pEv->time%60000000)/1000000); int milliseconds = (int)((pEv->time%1000000)/1000); float position = (evTime - time) * scrollSpeed; MFVector pos; MFView_TransformPoint3DTo2D(MakeVector(halfFB + 0.2f, 0.0f, position), &pos); pos.y -= 12.0f; MFFont_DrawTextf(pText, pos, 24.0f, MakeVector(0,0.5f,0,1), "A: %02d:%02d.%03d\n %s: %g", minutes, seconds, milliseconds, MFTranslation_GetString(pStrings, TRACK_BPM), (float)pEv->parameter * 0.001f); } else if(pEv->event == GHE_TimeSignature) { float position = (evTime - time) * scrollSpeed; MFVector pos; MFView_TransformPoint3DTo2D(MakeVector(-halfFB - 0.2f, 0.0f, position), &pos); const char *pString = MFStr("TS: %d/4", pEv->parameter); pos.x -= MFFont_GetStringWidth(pText, pString, 24.0f); pos.y -= 12.0f; MFFont_DrawTextf(pText, pos, 24.0f, MFVector::yellow, pString); } } pEv = pEv->Next(); } // render events pEv = pSong->events.GetNextEvent(bottomTick); int lastChecked = -1; float yEventOffset = -12.0f; while(pEv && pEv->time < topTimeus) { float evTime = GETSECONDS(pEv->time); if(evTime > bottomTime) { if(pEv->event == GHE_Event) { if(lastChecked != pEv->tick) { yEventOffset = -12.0f; lastChecked = pEv->tick; if(pSong->sync.FindEvent(GHE_TimeSignature, pEv->tick, 0)) { yEventOffset -= 24.0f; } } float position = (evTime - time) * scrollSpeed; MFVector pos; MFView_TransformPoint3DTo2D(MakeVector(-halfFB - 0.2f, 0.0f, position), &pos); if(!MFString_CompareN(pEv->GetString(), "section ", 8)) { // draw a line across? pos.x -= MFFont_GetStringWidth(pText, &pEv->GetString()[8], 24.0f); pos.y += yEventOffset; MFFont_DrawTextf(pText, pos, 24.0f, MFVector::blue, &pEv->GetString()[8]); } else { pos.x -= MFFont_GetStringWidth(pText, pEv->GetString(), 24.0f); pos.y += yEventOffset; MFFont_DrawTextf(pText, pos, 24.0f, MFVector::white, pEv->GetString()); } yEventOffset -= 24.0f; } } pEv = pEv->Next(); } // render track events pEv = pSong->notes[track].GetNextEvent(bottomTick); lastChecked = -1; yEventOffset = -12.0f; while(pEv && pEv->time < topTimeus) { float evTime = GETSECONDS(pEv->time); if(evTime > bottomTime) { if(pEv->event == GHE_Event) { if(lastChecked != pEv->tick) { yEventOffset = -12.0f; lastChecked = pEv->tick; if(pSong->sync.FindEvent(GHE_TimeSignature, pEv->tick, 0)) { yEventOffset -= 24.0f; } GHEvent *pOther = pSong->events.FindEvent(GHE_Event, pEv->tick, 0); while(pOther && pOther->tick == pEv->tick) { yEventOffset -= 24.0f; pOther = pOther->Next(); } } float position = (evTime - time) * scrollSpeed; MFVector pos; MFView_TransformPoint3DTo2D(MakeVector(-halfFB - 0.2f, 0.0f, position), &pos); pos.x -= MFFont_GetStringWidth(pText, pEv->GetString(), 24.0f); pos.y += yEventOffset; MFFont_DrawTextf(pText, pos, 24.0f, MakeVector(0.6f, 0.8f, 1.0f, 1.0f), pEv->GetString()); yEventOffset -= 24.0f; } } pEv = pEv->Next(); } MFView_Pop(); }