//------------------------------------------------------------------- // pcspinet.cpp // // This program shows an image of a spinet piano keyboard with // 64 keys, as a starting point for the 'tunetool.cpp' program // to be completed as Project 2. (Here the console's keyboard // (i.e., the 'stdin' device) operates in non-canonical mode.) // // compile using: $ g++ pcspinet.cpp int86.cpp -o pcspinet // // programmer: ALLAN CRUSE // written on: 20 SEP 2005 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for lseek() #include // for tcgetattr(), tcsetattr() #include // for mmap() #include "int86.h" // for init8086(), int86() #define VRAM_BASE_FOR_SVGA 0xA0000000 #define NUM_WHITEKEYS 38 #define NUM_BLACKKEYS 26 #define NUM_PIANOKEYS 64 #define MAX_KEYHEIGHT 80 typedef unsigned char u8; u8 *vram = (u8*)VRAM_BASE_FOR_SVGA; struct vm86plus_struct vm; int vesa_mode = 0x4103, hres = 800, vres = 600; /* ** Here is our description for the piano keyboard's image-elements. */ typedef char * KEYGLYPH[ MAX_KEYHEIGHT ]; typedef struct { int x, y; } POINT; typedef struct { int xmin, ymin, xmax, ymax; } RECT; typedef struct { u8 bg, fg, hi, dn; } COLORTBL; typedef struct { RECT rect; KEYGLYPH *bits; COLORTBL *ct; } ICON; typedef struct { double hertz; ICON icon; int entered; } PIANOKEY; typedef struct { RECT board; PIANOKEY key[ NUM_PIANOKEYS ]; } KEYBOARD; const int white_wide = 18, white_high = MAX_KEYHEIGHT; const int black_wide = 10, black_high = MAX_KEYHEIGHT/2; const int board_wide = white_wide * NUM_WHITEKEYS; const int board_high = white_high; KEYGLYPH blackglyph, whiteglyphL, whiteglyphM, whiteglyphR, whiteglyph; COLORTBL whitekey = { 0, 15, 7, 8 }; COLORTBL blackkey = { 0, 0, 8, 7 }; KEYBOARD keyboard; void draw_icon( ICON icon ) { COLORTBL *ct = icon.ct; KEYGLYPH *kg = icon.bits; RECT r = icon.rect; int wide = r.xmax - r.xmin, high = r.ymax - r.ymin; u8 *dstn = vram + r.ymin * hres + r.xmin; for (int y = 0; y < high; y++) { char *map = (*kg)[ y ]; for (int x = 0; x < wide; x++) switch ( map[ x ] ) { case '2': dstn[ y * hres + x ] = ct->fg; break; case '1': dstn[ y * hres + x ] = ct->bg; break; } } } void frame_rect( RECT r, u8 color ) { int x = r.xmin, y = r.ymin; do { vram[ y * hres + x ] = color; ++x; } while ( x < r.xmax ); do { vram[ y * hres + x ] = color; ++y; } while ( y < r.ymax ); do { vram[ y * hres + x ] = color; --x; } while ( x > r.xmin ); do { vram[ y * hres + x ] = color; --y; } while ( y > r.ymin ); } void fill_rect( RECT r, u8 color ) { for (int y = r.ymin; y < r.ymax; y++) for (int x = r.xmin; x < r.xmax; x++) vram[ y * hres + x ] = color; } int main( int argc, char **argv ) { // establish noncanonical keyboard input struct termios origtty; tcgetattr( STDIN_FILENO, &origtty ); struct termios worktty = origtty; worktty.c_lflag &= ~( ECHO | ICANON ); worktty.c_cc[ VMIN ] = 1; worktty.c_cc[ VTIME ] = 0; tcsetattr( STDIN_FILENO, TCSAFLUSH, &worktty ); // memory-map the display-memory into user-space int vd = open( "/dev/vram", O_RDWR ); if ( vd < 0 ) { perror( "/dev/vram" ); exit(1); } int size = lseek( vd, 0, SEEK_END ); int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)VRAM_BASE_FOR_SVGA; if ( mmap( mm, size, prot, flag, vd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // initialize keyboard data-structures keyboard.board.xmin = (hres - board_wide)/2; keyboard.board.ymin = (vres - board_high)/2; keyboard.board.xmax = keyboard.board.xmin + board_wide; keyboard.board.ymax = keyboard.board.ymin + board_high; for (int k = 0; k < NUM_PIANOKEYS; k++) { if ( k == NUM_PIANOKEYS-1 ) { keyboard.key[ k ].icon.ct = &whitekey; keyboard.key[ k ].icon.bits = &whiteglyph; } else if ( k == 0 ) { keyboard.key[ k ].icon.ct = &whitekey; keyboard.key[ k ].icon.bits = &whiteglyphL; } else switch ( k % 12 ) { case 1: case 4: case 6: case 9: case 11: keyboard.key[ k ].icon.ct = &blackkey; keyboard.key[ k ].icon.bits = &blackglyph; break; case 0: case 5: case 10: // tween blacks: A, D, and G keyboard.key[ k ].icon.ct = &whitekey; keyboard.key[ k ].icon.bits = &whiteglyphM; break; case 2: case 7: // right of a black: B and E keyboard.key[ k ].icon.ct = &whitekey; keyboard.key[ k ].icon.bits = &whiteglyphR; break; case 3: case 8: // left of a black: C and F keyboard.key[ k ].icon.ct = &whitekey; keyboard.key[ k ].icon.bits = &whiteglyphL; break; } } // initialize the keyglyph bitmaps for (int y = 0; y < MAX_KEYHEIGHT; y++) { if ( y < black_high ) { blackglyph[y] = "22222222220000000000"; whiteglyphL[y] = "22222222222210000000"; whiteglyphM[y] = "00000122222210000000"; whiteglyphR[y] = "00000122222222222100"; whiteglyph[y] = "22222222222222222100"; } else { blackglyph[y] = "00000000000000000000"; whiteglyphL[y] = "22222222222222222100"; whiteglyphM[y] = "22222222222222222100"; whiteglyphR[y] = "22222222222222222100"; whiteglyph[y] = "22222222222222222100"; } } // initialize the key-boundaries int x_white = keyboard.board.xmin; int y_white = keyboard.board.ymin; int black_backup = 1 + (white_wide - black_wide)/2; for (int k = 0; k < NUM_PIANOKEYS; k++) { PIANOKEY *pk = &keyboard.key[ k ]; if ( pk->icon.ct == &whitekey ) { pk->icon.rect.xmin = x_white; pk->icon.rect.ymin = y_white; pk->icon.rect.xmax = x_white + white_wide; pk->icon.rect.ymax = y_white + white_high; x_white += white_wide; } else { int x_black = x_white - black_backup; int y_black = y_white; pk->icon.rect.xmin = x_black; pk->icon.rect.ymin = y_black; pk->icon.rect.xmax = x_black + black_wide; pk->icon.rect.ymax = y_black + black_high; } } // enter graphics mode init8086(); vm.regs.eax = 0x4F02; vm.regs.ebx = vesa_mode; int86( 0x10, vm ); // draw a white screen border RECT border = { 0, 0, hres-1, vres-1 }; frame_rect( border, 15 ); getchar(); // draw the keyboard's background and all its keys fill_rect( keyboard.board, 0 ); for (int k = 0; k < NUM_PIANOKEYS; k++) draw_icon( keyboard.key[ k ].icon ); getchar(); // leave graphics mode vm.regs.eax = 0x0003; int86( 0x10, vm ); tcsetattr( STDIN_FILENO, TCSAFLUSH, &origtty ); printf( "\n" ); }