1: /*
     2:  *  Guitar-ZyX(tm)::MasterControlProgram - portable guitar F/X controller
     3:  *  Copyright (C) 2009  Douglas McClendon
     4:  *
     5:  *  This program is free software: you can redistribute it and/or modify
     6:  *  it under the terms of the GNU General Public License as published by
     7:  *  the Free Software Foundation, version 3 of the License.
     8:  *
     9:  *  This program is distributed in the hope that it will be useful,
    10:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    11:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12:  *  GNU General Public License for more details.
    13:  *
    14:  *  You should have received a copy of the GNU General Public License
    15:  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16: */
    17: /*
    18: #############################################################################
    19: #############################################################################
    20: ## 
    21: ## gzmcpc::mode__tpw__jam: TouchPadWhammy Jamming Mode (i.e. the mcp's soul)
    22: ##
    23: #############################################################################
    24: ##
    25: ## Copyright 2008-2009 Douglas McClendon <dmc AT filteredperception DOT org>
    26: ##
    27: #############################################################################
    28: #############################################################################
    29: #
    30: */
    31: 
    32: 
    33: 
    34: 
    35: #include <nds.h> 
    36: 
    37: #include <stdio.h> 
    38: 
    39: 
    40: #include "debug.h" 
    41: 
    42: #include "dmc.h" 
    43: 
    44: #include "graphics.h" 
    45: 
    46: #include "input.h" 
    47: 
    48: #include "mcp.h" 
    49: 
    50: #include "metrognome.h" 
    51: 
    52: #include "modes.h" 
    53: 
    54: #include "mode__get_update.h" 
    55: 
    56: #include "mode__tpw__jam.h" 
    57: 
    58: #include "network.h" 
    59: 
    60: #include "rak.h" 
    61: 
    62: #include "sound.h" 
    63: 
    64: #include "time.h" 
    65: 
    66: 
    67: #include "sounds.h" 
    68: 
    69: #include "sounds_bin.h" 
    70: 
    71: #include "resources/bitmaps/dlava.h" 
    72: 
    73: 
    74: 
    75: uint8 comb_charge[COMB_WIDTH][COMB_HEIGHT];
    76: 
    77: unsigned char x3d_intensity = 0;
    78: 
    79: v16 model_xcenter = (MODEL_XMAX + MODEL_XMIN) / 2;
    80: v16 model_ycenter = (MODEL_YMAX + MODEL_YMIN) / 2;
    81: v16 model_zcenter = (MODEL_ZMAX + MODEL_ZMIN) / 2;
    82: v16 model_width = MODEL_XMAX - MODEL_XMIN;
    83: v16 model_height = MODEL_YMAX - MODEL_YMIN;
    84: v16 model_depth = MODEL_ZMAX - MODEL_ZMIN;
    85: 
    86: 
    87: int touch_whammy_enabled = 0;
    88: int touch_whammy_x_midi_parm = DEFAULT_X_PARM;
    89: int touch_whammy_y_midi_parm = DEFAULT_Y_PARM;
    90: 
    91: int current_preset = 1;
    92: 
    93: int button_x_preset_num = CM_PRESET_X_NUM;
    94: int button_y_preset_num = CM_PRESET_Y_NUM;
    95: int button_a_preset_num = CM_PRESET_A_NUM;
    96: int button_b_preset_num = CM_PRESET_B_NUM;
    97: 
    98: int vstrobe_bpm = VSTROBE_DEFAULT_BPM;
    99: int vstrobe_enabled = 0;
   100: int user_vstrobe_enabled = 0;
   101: 
   102: 
   103: 
   104: 
   105: 
   106: void mode__tpw__jam___init(void) {
   107: 
   108:   // set main screen to be on the top lcd display
   109:   lcdMainOnBottom();
   110: 
   111:   videoSetMode(MODE_5_3D);
   112: 
   113:   // EXPERIMENT: 3D examples don't show this as necessary, but maybe
   114:   //             it will fix my issue with intro mode after this 
   115:   //             not showing the texture
   116:   // RESULT: no difference
   117:   // map main screen background fourth (128k) region to vram bank A
   118:   vramSetBankA(VRAM_A_MAIN_BG_0x06060000);
   119: 
   120:   // initialize 3D bottom (touch) screen graphics subsystem
   121:   // XXX: this is now a mode specific function, probably should reside in
   122:   //      this file.
   123:   gzmcpc_init_3d();
   124: 
   125:   // return to desired state
   126:   videoSetModeSub(MODE_5_2D);
   127: 
   128:   // use vram bank c for the secondary/sub-screen(background)
   129:   vramSetBankC(VRAM_C_SUB_BG);
   130: 
   131:   mcp_console_init(&top_screen, 
   132: 		   MCP_SUB_SCREEN,
   133: 		   0,
   134: 		   1,
   135: 		   1,
   136: 		   BgType_Text4bpp, 
   137: 		   BgSize_T_256x256, 
   138: 		   31, 
   139: 		   0);
   140: 
   141:   consoleSelect(&top_screen);
   142: 
   143:   bgSetPriority(top_screen.bgId, 0);
   144: 
   145:   bgShow(top_screen.bgId);
   146: 
   147:   // default to fully faded to black (31) not the opposite (0)
   148:   REG_BLDY_SUB = 31;
   149:   // fade the subscreen background to/from black, layer 3
   150:   REG_BLDCNT_SUB = BLEND_FADE_BLACK | BLEND_SRC_BG3;
   151: 
   152:   // note: using offset=4, because 4 will be 64k offset, where 31 above is 62k
   153:   // (thus above using only 2k? seems plausible with tiles for console text chars
   154:   bgs3 = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 4, 0);
   155:   // its initial priority, lowest (to emphasize lack of other enabled layers)
   156:   // priorities 0..3, 0 highest priority
   157:   bgSetPriority(bgs3, 2);
   158: 
   159:   bgHide(bgs3);
   160: 
   161:   // as per libnds doc on dma
   162:   DC_FlushRange(dlavaBitmap, 256*256);
   163:   dmaCopy(dlavaBitmap, bgGetGfxPtr(bgs3), 256*256);
   164:   DC_FlushRange(dlavaPal, 256*2);
   165:   dmaCopy(dlavaPal, BG_PALETTE_SUB, 256*2);
   166:   
   167:   bgShow(bgs3);
   168: 
   169: }
   170: 
   171: void mode__tpw__jam___top_renderer(void) {
   172:   
   173:   long msphase, phase;
   174:   //  long phase_prev, phase_next;
   175:   char stringthing[MAX_TEXT_OUTPUT_LINE_SIZE];
   176:   int vstrobe_period_ms;
   177: 
   178:   unsigned char t_font_int;
   179:   int t_blend;
   180: 
   181:   // 
   182:   // initialize to unfaded values
   183:   // 
   184:   t_blend = 0;
   185:   t_font_int = (unsigned char)((int)font_intensity * 1);
   186: 
   187:   // 
   188:   // do bg fade-in
   189:   // 
   190:   if (mode_ms < TPW__JAM__BOT_BG_FADE_IN_START_MS) {
   191:     // pre fade-in
   192:     t_blend = 31;
   193:   } else if (mode_ms < (TPW__JAM__BOT_BG_FADE_IN_START_MS + 
   194: 			TPW__JAM__BOT_BG_FADE_IN_DURATION_MS)) {
   195:     // main screen bg fade-in
   196:     t_blend = 31 - ((mode_ms - TPW__JAM__BOT_BG_FADE_IN_START_MS) * 31 / 
   197: 		    TPW__JAM__BOT_BG_FADE_IN_DURATION_MS);
   198: 
   199:   } 
   200: 
   201:   // 
   202:   // do text fade-in
   203:   // 
   204:   if (mode_ms < TPW__JAM__BOT_TXT_FADE_IN_START_MS) {
   205:     // pre fade-in
   206:     t_font_int = 0;
   207:   } else if (mode_ms < (TPW__JAM__BOT_TXT_FADE_IN_START_MS + 
   208: 			TPW__JAM__BOT_TXT_FADE_IN_DURATION_MS)) {
   209:     t_font_int = (unsigned char)((int)(font_intensity) * 
   210: 			       (mode_ms - TPW__JAM__BOT_TXT_FADE_IN_START_MS) / 
   211: 			       TPW__JAM__BOT_TXT_FADE_IN_DURATION_MS);
   212:   } 
   213: 
   214: 
   215:   //
   216:   // do fadeout, possibly overriding above
   217:   //
   218:   if (mode != next_mode) {
   219:     // fade-out
   220:     if ((mode_ms - exit_mode_ms) < TPW__JAM__BOT_BG_FADE_OUT_DURATION_MS) {
   221:       t_blend = ((mode_ms - exit_mode_ms) * 
   222: 		      31 / TPW__JAM__BOT_BG_FADE_OUT_DURATION_MS);
   223:     } else {
   224:       t_blend = 31;
   225:     }
   226:     // only fadeout
   227:     t_blend = MAX(t_blend, mcp_get_blend(MCP_SUB_SCREEN));
   228: 
   229:     if ((mode_ms - exit_mode_ms) < TPW__JAM__BOT_TXT_FADE_OUT_DURATION_MS) {
   230:       t_font_int = (unsigned char)((int)(font_intensity) * 
   231: 				 (TPW__JAM__BOT_TXT_FADE_OUT_DURATION_MS - (mode_ms - exit_mode_ms)) / 
   232: 				 TPW__JAM__BOT_TXT_FADE_OUT_DURATION_MS);
   233:     } else {
   234:       t_font_int = 0;
   235:     }
   236:     // only fadeout
   237:     t_font_int = MIN(t_font_int, RGB15_TO_G5(BG_PALETTE_SUB[255]));
   238:   }
   239: 
   240:   mcp_set_blend(MCP_SUB_SCREEN,
   241: 		t_blend);
   242:   // set the font color from the calculated intensity (greenish)
   243:   BG_PALETTE_SUB[255] = RGB15(t_font_int / 3,
   244: 			      t_font_int,
   245: 			      t_font_int / 3);
   246: 
   247: 
   248:   // XXX: moving this hear causes top screen render lockup after server connect?????
   249:   //      (a couple other lines of the same code is below)
   250:   //  if (time_val_compare(next_top_render, num_ticks) <= 0) {
   251:   //    return;
   252:   //  }
   253: 
   254: 
   255:   // XXX: all below might better be done once at modification time
   256:   textout(TLT_FX_MODE, "%s", 
   257:   	  rak_preset_labels[cstate_preset - 1]);
   258: 
   259:   textout(TLT_TOUCH_VALXP, "%s", 
   260:   	  get_rak_midi_label(touch_whammy_x_midi_parm));
   261: 
   262:   textout(TLT_TOUCH_VALYP, "%s", 
   263:     	  get_rak_midi_label(touch_whammy_y_midi_parm));
   264: 
   265: 
   266: #define VSTROBE_NUM_CHARS 22 
   267: 
   268:   // XXX could do this calculation at vstrobe_bpm modification time instead
   269:   //     of every frame
   270:   vstrobe_period_ms = (int)(
   271: 			    (
   272: 			     1.0f / 
   273: 			     (((float)vstrobe_bpm / 
   274: 			       (float)VSTROBE_NUM_CHARS) / 60.0f)
   275: 			     ) * 1000.0f
   276: 			    );
   277: 
   278:   // XXX and these as well
   279:   textout(TLT_TOUCH_VAL, 
   280: 	  ":X=%02d:/\\/:Y=%02d:", 
   281: 	  cstate_wpx * 100 / 128,
   282: 	  cstate_wpy * 100 / 128);
   283: 
   284:   if (!vstrobe_enabled) {
   285:     textout(TLT_AESTHETIC, " /\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/");
   286:   } else {
   287: 
   288:     // age related death problem here (overflow the long)
   289:     msphase = ((num_ticks.s * 1000) + num_ticks.ms) % vstrobe_period_ms;
   290:     
   291:     phase = (int)(((float)msphase / 
   292: 		   (float)vstrobe_period_ms) 
   293: 		  * (float)VSTROBE_NUM_CHARS * 2.0f);
   294:     
   295:     if (phase >= VSTROBE_NUM_CHARS) {
   296:       phase = (VSTROBE_NUM_CHARS) - (phase - VSTROBE_NUM_CHARS);
   297:     }
   298:     
   299:     // this is the old single direction wrapping method
   300:     //if (phase == 0) {
   301:     //phase_prev = VSTROBE_NUM_CHARS - 1;
   302:     //} else {
   303:     //phase_prev = phase - 1;
   304:     //}
   305:     
   306:     //if (phase == (VSTROBE_NUM_CHARS - 1)) {
   307:     //phase_next = 0;
   308:     //} else {
   309:     //phase_next = phase + 1;
   310:     //}
   311:     
   312:     // dmcnote: looked it up, no -1 here, max size includes null char at end
   313:     snprintf(stringthing, MAX_TEXT_OUTPUT_LINE_SIZE,
   314: 	     " /\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/");
   315: 
   316:     stringthing[phase + 2] = '-';
   317:     stringthing[phase + 3] = '<';
   318:     stringthing[phase + 4] = '=';
   319:     stringthing[phase + 5] = '>';
   320:     stringthing[phase + 6] = '-';
   321:     
   322:     textout(TLT_AESTHETIC, "%s", stringthing);
   323: 
   324:   } // end if/else vstrobe_enabled
   325: 
   326:   // XXX: same experiment as above
   327:   //  next_top_render = time_val_add_ms(next_top_render, 1000 / TOP_RENDER_RATE);
   328: 
   329:   // actually render the text output
   330:   render_textout();
   331: 
   332: }
   333: 
   334: void mode__tpw__jam___bot_renderer(void) {
   335: 
   336:   int i, j;
   337: 
   338:   uint8 cursor_r;
   339:   uint8 cursor_g;
   340:   uint8 cursor_b;
   341:   uint8 cursor_a;
   342:   uint8 cursor_center_r;
   343:   uint8 cursor_center_g;
   344:   uint8 cursor_center_b;
   345:   uint8 cursor_center_a;
   346: 
   347: 
   348:   int xcomb_row_height;
   349:   int xcomb_col_width;
   350:   int xtouch_pos_y;
   351:   int xtouch_pos_x;
   352:   int xcomb_row_cursor;
   353:   int xcomb_col_cursor;
   354: 
   355:   int tmprate;
   356:   int tmpvolume;
   357:   int tmppanning;
   358: 
   359:   unsigned char t_3d_int;
   360: 
   361: 
   362:   //
   363:   // handle fade with intensity variable
   364:   //
   365: 
   366:   // initialize to unfaded value
   367:   t_3d_int = TPW_3D_MAX_INTENSITY;
   368: 
   369:   // 
   370:   // do text fade-in
   371:   // 
   372:   if (mode_ms < TPW__JAM__BOT_3D_FADE_IN_START_MS) {
   373:     // pre fade-in
   374:     t_3d_int = 0;
   375:   } else if (mode_ms < (TPW__JAM__BOT_3D_FADE_IN_START_MS + 
   376: 			TPW__JAM__BOT_3D_FADE_IN_DURATION_MS)) {
   377:     t_3d_int = (unsigned char)((mode_ms - TPW__JAM__BOT_3D_FADE_IN_START_MS) * 
   378: 			       255 / 
   379: 			       TPW__JAM__BOT_3D_FADE_IN_DURATION_MS);
   380:   } 
   381: 
   382: 
   383:   //
   384:   // do fadeout, possibly overriding above
   385:   //
   386:   if (mode != next_mode) {
   387: 
   388:     if ((mode_ms - exit_mode_ms) < TPW__JAM__BOT_3D_FADE_OUT_DURATION_MS) {
   389:       t_3d_int = (unsigned char)((TPW__JAM__BOT_3D_FADE_OUT_DURATION_MS - 
   390: 				  (mode_ms - exit_mode_ms)) * 255 / 
   391: 				 TPW__JAM__BOT_3D_FADE_OUT_DURATION_MS);
   392:     } else {
   393:       t_3d_int = 0;
   394:     }
   395:     // only fadeout
   396:     t_3d_int = MIN(t_3d_int, x3d_intensity);
   397:   }
   398: 
   399:   x3d_intensity = t_3d_int;
   400: 
   401:   // update comb charge matrix
   402:   // recharge
   403: 
   404:   // 1024 is a fixed point scaling thing
   405:   // take into account upper and lower half rows
   406:   xcomb_row_height = 192 * 1024 / (COMB_HEIGHT - 1);
   407:   xtouch_pos_y = (touch_pos_y * 1024) + (xcomb_row_height >> 1);
   408:   xcomb_row_cursor = xtouch_pos_y / xcomb_row_height;
   409:   // XXX error check on xcomb_row_cursor < COMB_HEIGHT
   410: 
   411:   xcomb_col_width = 256 * 1024 / COMB_WIDTH;
   412:   xtouch_pos_x = (touch_pos_x * 1024);
   413:   xtouch_pos_x += (xcomb_col_width >> 1);
   414:   if (xcomb_row_cursor % 2) {
   415:     // odd row, shift left half a col width
   416:     if (xtouch_pos_x > (xcomb_col_width >> 1)) {
   417:       xtouch_pos_x -= (xcomb_col_width >> 1);
   418:     } else {
   419:       xtouch_pos_x = 0;
   420:     }
   421:   }
   422:   xcomb_col_cursor = xtouch_pos_x / xcomb_col_width;
   423:   // XXX
   424:   if (xcomb_col_cursor >= COMB_WIDTH) xcomb_col_cursor--;
   425: 
   426:   // seems to be all good
   427:   //  textout(TLT_STATUS, ":::%d:::%d:::", xcomb_row_cursor, xcomb_col_cursor);
   428:   // XXX: clear up inversion confusion here or elsewhere, probably all
   429:   //      kinds of ways to make the code more readable with utility functions,
   430:   //      and better performance being careful where values are calculated 
   431:   //      and how often.
   432:   if (comb_charge[(COMB_WIDTH - 1) - xcomb_col_cursor][(COMB_HEIGHT - 1) - xcomb_row_cursor] < 224) {
   433:     //
   434:     // play metrognome
   435:     //
   436: 
   437:     // save standard parameters for the effect
   438:     tmprate = sounds[SFX_METROGNOME].rate; // 1024
   439:     tmpvolume = sounds[SFX_METROGNOME].volume; // 255
   440:     tmppanning = sounds[SFX_METROGNOME].panning; // 127
   441: 
   442:     sounds[SFX_METROGNOME].volume = 255 * xcomb_row_cursor / COMB_HEIGHT; // 255
   443: 
   444:     for (i = 0 ; i < (COMB_WIDTH >> 1) ; i++) {
   445:       sounds[SFX_METROGNOME].rate = (int)((float)sounds[SFX_METROGNOME].rate * 1.059f);
   446:     }
   447:     for (i = 0 ; i < xcomb_col_cursor ; i++) {
   448:       sounds[SFX_METROGNOME].rate = (int)((float)sounds[SFX_METROGNOME].rate / 1.059f);
   449:     }
   450: 
   451:     //    sounds[SFX_METROGNOME].panning = 255 - (255 * xcomb_col_cursor / COMB_WIDTH); // 127
   452:     mmEffectEx(&sounds[SFX_METROGNOME]);
   453:     // restore standard parameters for the effect
   454:     sounds[SFX_METROGNOME].rate = tmprate;
   455:     sounds[SFX_METROGNOME].volume = tmpvolume;
   456:     sounds[SFX_METROGNOME].panning = tmppanning;
   457:     
   458:   }
   459:   comb_charge[(COMB_WIDTH - 1) - xcomb_col_cursor][(COMB_HEIGHT - 1) - xcomb_row_cursor] = 255;
   460: 
   461:   // update comb charge matrix
   462:   for (i = 0; i < COMB_WIDTH ; i++) { 
   463:     for (j = 0; j < COMB_WIDTH ; j++) { 
   464:       
   465:       // decay
   466:       if (comb_charge[i][j] >= 2) {
   467: 	comb_charge[i][j] = comb_charge[i][j] - 2;
   468:       } else {
   469: 	comb_charge[i][j] = 0;
   470:       }
   471:     }
   472:   }
   473: 
   474:   // refactor to comb_row(touch_pos_x_val) and column/y
   475:   
   476:   
   477:   init_modelview_matrix();
   478: 
   479:   // NDS does this automagically, and current api won't allow it
   480:   // clear color and depth buffers
   481:   //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   482:   // maybe redundant, 0..31 for rgba
   483:   //  glClearColor(0, 0, 0, 31);
   484: 
   485: 
   486:   // draw a cool cyber-honeycomb
   487:   // including trippy charge tracer and background effects
   488:   draw_simple_hex_grid(COMB_WIDTH,
   489: 		       COMB_HEIGHT,
   490: 		       RGB15(x3d_intensity >> 3,
   491: 			     x3d_intensity >> 3,
   492: 			     x3d_intensity >> 3));
   493: 
   494:   // define the cursor inner/outter colors based on current state
   495:   if (touch_whammy_enabled) {
   496:     cursor_r = (uint8)(0.8f * cursor_intensity * 256);
   497:     cursor_g = (uint8)(0.2f * cursor_intensity * 256);
   498:     cursor_b = (uint8)(0.2f * cursor_intensity * 256);
   499:     cursor_a = 0;
   500:     cursor_center_r = 255;
   501:     cursor_center_g = 255;
   502:     cursor_center_b = 255;
   503:     cursor_center_a = 255;
   504:   } else {
   505:     cursor_r = (uint8)(0.2f * cursor_intensity * 256);
   506:     cursor_g = (uint8)(0.2f * cursor_intensity * 256);
   507:     cursor_b = (uint8)(0.7f * cursor_intensity * 256);
   508:     cursor_a = 0;
   509:     cursor_center_r = 0;
   510:     cursor_center_g = 0;
   511:     cursor_center_b = 0;
   512:     cursor_center_a = 0;
   513:   }
   514: 
   515:   // draw touchwhammypad cursor
   516:   draw_hex(MODEL_XMAX - model_width * touch_pos_x / 256,
   517: 	   MODEL_YMAX - model_height * touch_pos_y / 192,
   518: 	   MODEL_ZMAX - model_depth / 4,
   519: 	   CURSOR_RADIUS,
   520: 	   cursor_rotation,
   521: 	   cursor_center_r,
   522: 	   cursor_center_g,
   523: 	   cursor_center_b,
   524: 	   cursor_center_a,
   525: 	   cursor_r,
   526: 	   cursor_g,
   527: 	   cursor_b,
   528: 	   cursor_a,
   529: 	   0,
   530: 	   0,
   531: 	   0,
   532: 	   255,
   533: 	   RGB15(x3d_intensity >> 3,
   534: 		 x3d_intensity >> 3,
   535: 		 x3d_intensity >> 3));
   536: 
   537: }
   538: 
   539: void mode__tpw__jam___input_handler(void) {
   540: 
   541:   //
   542:   // handle input
   543:   //
   544: 
   545:   // XXX refactor into classifcation/enumeration of 'interesting events
   546:   //     watched for', and then have function to register an event
   547:   //     handler for each.  I.e. layer of abstraction between tasks and
   548:   //     the input event they are mapped to (then expose that in configfile,
   549:   //     and/or config menu)
   550: 
   551:   // At the outermost layer of this nest, are all combinations of modifiers
   552:   // I.e. heldkey combinations that are meant to do interesting things. 
   553:   // After those cases are handled, then the normal non-modified cases are
   554:   // handled, and the assumption is that if we are in a modifier situation,
   555:   // we only want that code to be looked at.
   556:   // note: potential exception: touchpad held perhaps should not interfere
   557:   //       simultaneous other inputs.
   558:   if ((heldkeys & KEY_L) && (heldkeys & KEY_R)) {
   559:     //
   560:     // held(L)+held(R)+something
   561:     //
   562:     
   563:     //: The adjustable metrognome is currently the pro only feature.
   564:     //: Please, do what you can to help me scrape by enough dough
   565:     //: so that I can add more and more features to the pro version
   566:     //: which will find their way into the GPL version after no more
   567:     //: than 7 years (and probably much MUCH sooner than that).
   568: #ifdef IM_POOR_OR_LICENSED_OR_NOT 
   569:     if (downkeys & KEY_LEFT) {
   570:       // XXX no limits yet
   571:       astrobe_bpm -= 1;
   572:       textout(TLT_STATUS, "metrognome bpm: %d", astrobe_bpm);
   573:       // XXX tired, is this really useful??
   574:       //	heldover = IH_METROGNOME_DEC;
   575:       // XXX? constant: IH_METROGNOME_HELDOVER_RATE_HZ = 10?
   576:       heldover_sunset = time_val_add_ms(num_ticks, 224);
   577:     }
   578:     if (downkeys & KEY_RIGHT) {
   579:       astrobe_bpm += 1;
   580:       textout(TLT_STATUS, "metrognome bpm: %d", astrobe_bpm);
   581:       //	heldover = IH_METROGNOME_INC;
   582:       heldover_sunset = time_val_add_ms(num_ticks, 224);
   583:     }
   584: #endif //#ifdef  IM_POOR_OR_LICENSED_OR_NOT 
   585:     
   586:     if (downkeys & KEY_UP) {
   587:       textout(TLT_DEBUG, 
   588: 	      "mf:%d:mu:%d:",
   589: 	      get_mem_free(),
   590: 	      get_mem_used());
   591:       textout(TLT_MODE, 
   592: 	      "mf:%d:mu:%d:",
   593: 	      get_mem_free(),
   594: 	      get_mem_used());
   595:     }
   596:     
   597:     if (downkeys & KEY_DOWN) {
   598:     }
   599: 
   600:     if (downkeys & KEY_X) {
   601:       // experimental mode transition
   602:       system_xmode_new(MODE_INTRO__MAIN);
   603:       // XXX: perhaps imp fadeout(MODE_INTRO__MAIN), which sets mode vars, 
   604:       //      and idlefunc handles the fade
   605:     }
   606: 
   607:     if (downkeys & KEY_Y) {
   608:       // experimental mode transition
   609:       system_xmode_new(MODE_SSID__INPUT);
   610:     }
   611:     
   612:     if (downkeys & KEY_A) {
   613:       system_xmode_new(MODE_GET_UPDATE);
   614:     }
   615: 
   616:     if (downkeys & KEY_B) {
   617:       overwrite_self_with_update = 1;
   618:       system_xmode_new(MODE_GET_UPDATE);
   619:     }
   620: 
   621:     
   622:     if (downkeys & KEY_START) {
   623:       if (vstrobe_enabled) {
   624: 	textout(TLT_STATUS, "strobe disabled");
   625: 	vstrobe_enabled = 0;
   626: 	user_vstrobe_enabled = 1;
   627:       } else {
   628: 	textout(TLT_STATUS, "strobe enabled");
   629: 	vstrobe_enabled = 1;
   630: 	user_vstrobe_enabled = 1;
   631:       }
   632:     }
   633:     
   634:     if (downkeys & KEY_SELECT) {
   635:       if (astrobe_enabled) {
   636: 	textout(TLT_STATUS, "metrognome disabled");
   637: 	astrobe_enabled = 0;
   638:       } else {
   639: 	textout(TLT_STATUS, "metrognome enabled");
   640: 	astrobe_enabled = 1;
   641: 	next_metrognome_play = time_val_add_ms(num_ticks, 1000 * 60 / astrobe_bpm);
   642:       }
   643:     }
   644: 
   645:     // this is temporary anyway probably...
   646:     // only respect held(LR)+L|R for vstrobe bpm +/- if the user has toggled it at least once
   647:     if (user_vstrobe_enabled) {
   648:       
   649:       if (downkeys & KEY_DOWN) {
   650: 	// XXX no limits yet
   651: 	vstrobe_bpm -= 1;
   652: 	textout(TLT_STATUS, "strobe bpm: %d", vstrobe_bpm);
   653: 	heldover_sunset = time_val_add_ms(num_ticks, 224);
   654:       }
   655:       if (downkeys & KEY_UP) {
   656: 	vstrobe_bpm += 1;
   657: 	textout(TLT_STATUS, "strobe bpm: %d", vstrobe_bpm);
   658: 	heldover_sunset = time_val_add_ms(num_ticks, 224);
   659:       }
   660:       
   661:     } // end if (user_vstrobe_enabled)
   662:     
   663:   } else if (heldkeys & KEY_L) {
   664:     //
   665:     // held(L)+something
   666:     //
   667:     
   668:     // theory: held(L)+ABXY is mirrorly as nice as held(R)+LRUD
   669:     // (i.e. inverse of those should be rarely used UI things)
   670:     
   671:     if (downkeys & KEY_X) {
   672:       // XXX need to get MAX_PRESET from server
   673:       if (cstate_preset < MAX_PRESETS) {
   674: 	cstate_preset += 1;
   675: 	heldover_sunset = time_val_add_ms(num_ticks, 224);
   676:       }
   677:     }
   678:     
   679:     if (downkeys & KEY_B) {
   680:       if (cstate_preset > 1) {
   681: 	cstate_preset -= 1;
   682: 	heldover_sunset = time_val_add_ms(num_ticks, 224);
   683:       }
   684:     }
   685:     
   686:     if (downkeys & KEY_UP) {
   687:       debug_tweak_var++;
   688:       textout(TLT_STATUS, "dtv:%d:", debug_tweak_var);
   689:     }
   690:     
   691:     if (downkeys & KEY_DOWN) {
   692:       debug_tweak_var--;
   693:       textout(TLT_STATUS, "dtv:%d:", debug_tweak_var);
   694:     }
   695: 
   696:     if (downkeys & KEY_START) {
   697:     }
   698:     
   699:   } else if (heldkeys & KEY_R) {
   700:     //
   701:     // held(R)+something
   702:     //
   703:     
   704:     if (downkeys & KEY_LEFT) {
   705:       cursor_intensity -= 0.05f;
   706:       if (cursor_intensity < 0.2f) cursor_intensity = 0.2f;
   707:       heldover_sunset = time_val_add_ms(num_ticks, 100);
   708:     }
   709:     if (downkeys & KEY_RIGHT) {
   710:       cursor_intensity += 0.05f;
   711:       if (cursor_intensity > 0.8f) cursor_intensity = 0.8f;
   712:       heldover_sunset = time_val_add_ms(num_ticks, 100);
   713:     }
   714:     
   715:     if (downkeys & KEY_UP) {
   716:       if (font_intensity < FONT_INTENSITY_MAX) font_intensity++;
   717:       BG_PALETTE_SUB[255] = RGB15(font_intensity,
   718: 				  font_intensity,
   719: 				  font_intensity);
   720:       heldover_sunset = time_val_add_ms(num_ticks, 422);
   721:     }
   722:     if (downkeys & KEY_DOWN) {
   723:       if (font_intensity > FONT_INTENSITY_MIN) font_intensity--;
   724:       BG_PALETTE_SUB[255] = RGB15(font_intensity,
   725: 				  font_intensity,
   726: 				  font_intensity);
   727:       heldover_sunset = time_val_add_ms(num_ticks, 422);
   728:     }
   729:     
   730:   } else {
   731:     //
   732:     // no interesting modifer keys held
   733:     //
   734:     
   735:     if (downkeys & KEY_LEFT) {
   736:       if (touch_whammy_x_midi_parm > 0) {
   737: 	touch_whammy_x_midi_parm--;
   738: 	heldover_sunset = time_val_add_ms(num_ticks, 224);
   739:       }
   740:     }
   741:     
   742:     if (downkeys & KEY_RIGHT) {
   743:       if (touch_whammy_x_midi_parm < 127) {
   744: 	touch_whammy_x_midi_parm++;
   745: 	heldover_sunset = time_val_add_ms(num_ticks, 224);
   746:       }
   747:     }
   748:     
   749:     if (downkeys & KEY_DOWN) {
   750:       if (touch_whammy_y_midi_parm > 0) {
   751: 	touch_whammy_y_midi_parm--;
   752: 	heldover_sunset = time_val_add_ms(num_ticks, 224);
   753:       }
   754:     }
   755:     
   756:     if (downkeys & KEY_UP) {
   757:       if (touch_whammy_y_midi_parm < 127) {
   758: 	touch_whammy_y_midi_parm++;
   759: 	heldover_sunset = time_val_add_ms(num_ticks, 224);
   760:       }
   761:     }
   762:     
   763:     
   764:     if (downkeys & KEY_START) {
   765:     } // end if KEY_START
   766:     
   767:     if (downkeys & KEY_SELECT) {
   768:       if (touch_whammy_enabled) {
   769: 	touch_whammy_enabled = 0;
   770:       } else {
   771: 	touch_whammy_enabled = 1;
   772:       }
   773:     }
   774:     
   775:     // IMP TODO: need to get a name to preset hash with overridable values in defaults file...
   776:     if (downkeys & KEY_X) {
   777:       cstate_preset = button_x_preset_num;
   778:     }
   779:     
   780:     if (downkeys & KEY_Y) {
   781:       cstate_preset = button_y_preset_num;
   782:     }
   783:     
   784:     if (downkeys & KEY_A) {
   785:       cstate_preset = button_a_preset_num;
   786:     }
   787:     
   788:     if (downkeys & KEY_B) {
   789:       cstate_preset = button_b_preset_num;
   790:     }
   791:     
   792:   } // end button input handling
   793: 
   794: 
   795:   // touchpad handling is independent of modifiers (at the moment)
   796:   if ((downkeys & KEY_TOUCH) || (heldkeys & KEY_TOUCH)) {
   797:     //
   798:     // touchpad modifier, or slightly special, just downkey on the touchpad
   799:     //
   800:     
   801:     // the range seems to be x 253.0 y 189.0, 
   802:     // which is probably really 0-255,0-191
   803:     // touchdata.px scans left to right on the screen
   804:     // but I want it inverted, as the x whammy parm gets ramped up
   805:     // toward the nut, or ramped down toward the bridge
   806:     touch_pos_x = 255 - touchdata.px;
   807:     // touchdata.py scans top to bottom on the screen
   808:     // which is what I want as that means increasing as you stroke
   809:     // up toward your face (which is down on the NDS)
   810:     touch_pos_y = touchdata.py;
   811:     
   812:     // could have some ugly non float case logic to handle spreading
   813:     // out the couple lost values as we really end up maybe a few values
   814:     // shy of the full range on upper and lower (2..253) (4..189)
   815:     // (that was right after I calibrated, which didn't seem to help)
   816:     cstate_wpx = (int)(touch_pos_x / 2);
   817:     cstate_wpy = (int)(touch_pos_y * 4 / 3 / 2);
   818:     
   819:   } // end touchpad input handling
   820: 
   821: }
   822: 
   823: 
   824: void mode__tpw__jam___idle(void) {
   825:   if (cursor_rotating) {
   826:     cursor_rotation -= 1.23f;	
   827:     if (cursor_rotation < 0.0f) {
   828:       cursor_rotation += 360.0f;
   829:     }
   830:   }
   831: 
   832:   //
   833:   // handle fadeout
   834:   //
   835:   if (mode != next_mode) {
   836:     if (((mode_ms - exit_mode_ms) > TPW__JAM__TOP_BG_FADE_OUT_DURATION_MS) &&
   837: 	((mode_ms - exit_mode_ms) > TPW__JAM__BOT_BG_FADE_OUT_DURATION_MS) &&
   838: 	((mode_ms - exit_mode_ms) > TPW__JAM__BOT_TXT_FADE_OUT_DURATION_MS)) {
   839:       /*
   840:       // XXX: this should get moved elsewhere, and use dma
   841:       // XXX: not even remotely sure it is necessary or helps, just a theory
   842:       
   843:       // clear background image memory bank
   844:       // 256 * 256 * 2 = 128k 
   845:       dmaFillHalfWords(0,
   846: 		       (u16*)bgGetGfxPtr(bg3),
   847: 		       256 * 256 * 2);
   848:       //      memptr = (u16*)bgGetGfxPtr(bg3);
   849:       //      for (i = 0 ; i < (256 * 256) ; i++) memptr[i] = (u16)0;
   850:       
   851:       dmaFillHalfWords(0,
   852: 		       (u16*)bgGetGfxPtr(bgs1),
   853: 		       256 * 512 / 2);
   854: 
   855:       dmaFillHalfWords(0,
   856: 		       (u16*)bgGetGfxPtr(bgs0),
   857: 		       256 * 256 / 2);
   858:       */
   859:       system_xmode_real();
   860:     }
   861:   }
   862: 
   863:   if (mode == next_mode) {
   864:   }
   865: 
   866: }
   867: 
   868: 
   869: void mode__tpw__jam___exit(void) {
   870: 
   871: }
   872: 
   873: 
   874: /*
   875:   BCngU-0.1~
   876: 
   877:   B maj, lift bar/s1(thin).  then lift s2 and go to s543, then open,
   878:   then c, starting with middle, and upper, then lower
   879:   various n, n-1, n-2 repeat4, repeat3, then n-3, -2, n-1, and mz*pp
   880:  */
   881: