//-------------------------------------------------------------------- // wavprint.cpp // // This application submits a specified wavefile for printing on // a designated printer (or on the default printer if no printer // is specified). // // programmer: ALLAN CRUSE // written on: 20 AUG 2005 //-------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for read(), write(), close() #include // for strncpy(), strtok(), strcat() #define DOTS_PER_INCH 300 #define BANDWIDTH 2700 #define BANDS_PER_PAGE 4 typedef unsigned char BAND[ 0x40 ]; int main( int argc, char **argv ) { // check for required command-line argument if ( argc == 1 ) { fprintf( stderr, "Usage: %s ", argv[0] ); fprintf( stderr, "[ -P ] \n" ); exit(-1); } // attach '.wav' suffix to the filename argument char wavename[ 64 ] = {0}; strncpy( wavename, argv[1], 59 ); strtok( wavename, ". \n\t" ); strcat( wavename, ".wav" ); // open the '.wav' file and obtain its size (in bytes) int wav = open( wavename, O_RDONLY ); if ( wav < 0 ) { perror( wavename ); exit(-1); } int filesize = lseek( wav, 0, SEEK_END ); lseek( wav, 0, SEEK_SET ); fprintf( stderr, "\nFile is \'%s\' (%d bytes)\n", wavename, filesize ); // read and verify the RIFF chunk char chunk_name[4], chunk_type[4]; int chunk_size; read( wav, &chunk_name, 4 ); read( wav, &chunk_size, 4 ); read( wav, &chunk_type, 4 ); if ( strncmp( chunk_name, "RIFF", 4 ) != 0 ) { fprintf( stderr, "not a RIFF file\n" ); exit(-1); } if ( strncmp( chunk_type, "WAVE", 4 ) != 0 ) { fprintf( stderr, "not a WAVE file\n" ); exit(-1); } // find the file's format chunk int morebytes = filesize - 12; while ( morebytes > 8 ) { read( wav, &chunk_name, 4 ); read( wav, &chunk_size, 4 ); morebytes -= 8; if ( strncmp( chunk_name, "fmt ", 4 ) == 0 ) break; lseek( wav, chunk_size, SEEK_CUR ); morebytes -= chunk_size; } if ( morebytes < 16 ) { fprintf( stderr, "format not found\n" ); exit(-1); } // read the format-chunk's parameters short formatTag, nChannels, blockAlignmnt, bitsPerSample; int samplesPerSec, avBytesPerSec; read( wav, &formatTag, 2 ); read( wav, &nChannels, 2 ); read( wav, &samplesPerSec, 4 ); read( wav, &avBytesPerSec, 4 ); read( wav, &blockAlignmnt, 2 ); read( wav, &bitsPerSample, 2 ); lseek( wav, chunk_size - 16, SEEK_CUR ); morebytes -= chunk_size; // verify that format is 8-bit monoaural (for now) if (( formatTag != 1 )||( nChannels != 1 )||( blockAlignmnt != 1 )) { fprintf( stderr, "format not supported\n" ); exit(-1); } // advance to the wave 'data' while ( morebytes > 8 ) { read( wav, &chunk_name, 4 ); read( wav, &chunk_size, 4 ); morebytes -= 8; if ( strncmp( chunk_name, "data", 4 ) == 0 ) break; lseek( wav, chunk_size, SEEK_CUR ); morebytes -= chunk_size; } if ( morebytes < 16 ) { fprintf( stderr, "wave data not found\n" ); exit(-1); } // read the .wav data unsigned char *wavdata = (unsigned char *)malloc( chunk_size ); if ( !wavdata ) { perror( "malloc" ); exit(-1); } int wavebytes = read( wav, wavdata, chunk_size ); if ( wavebytes < 0 ) { perror( "read" ); free( wavdata ); exit(-1); } if ( wavebytes < chunk_size ) { fprintf( stderr, "read %d of ", wavebytes ); fprintf( stderr, "%d data bytes \n", chunk_size ); getchar(); } // setup the virtual wave-image int maxband = BANDS_PER_PAGE * BANDWIDTH; BAND *vimage = (BAND*)malloc( maxband * sizeof( BAND ) ); if ( !vimage ) { perror( "malloc" ); free( wavdata ); exit(-1); } for (int b = 0; b < maxband; b++) { int pcm = ( b < wavebytes ) ? (wavdata[ b ])/4 : 0; unsigned char *band = (unsigned char*)(vimage + b); for (int y = 0; y < 0x40; y++) { if ( (( pcm <= 0x20 )&&( pcm <= y )&&( y <= 0x20 )) || (( pcm >= 0x20 )&&( 0x20 <= y )&&( y <= pcm )) ) band[ y ] = 0x55; else band[ y ] = 0x00; } } // create a temporary file for output destined for the printer char tempname[] = "pclXXXXXX"; int pcl = mkstemp( tempname ); FILE *prn = fdopen( pcl, "w" ); if ( prn == NULL ) { fprintf( stderr, "could not create temporary file\n" ); exit(-1); } // printer initialization sequence fprintf( prn, "\eE" ); // 1. set print resolution (75, 100, 150, 300 dpi) fprintf( prn, "\e*t%dR", 300 ); // dots-per-inch // 2. set printer cursor to desired position fprintf( prn, "\e*p%dY\e*p%dX", 0, 0 ); fprintf( prn, "\e*p%dY\e*p%dX", 150, 150 ); // 3. set raster type fprintf( prn, "\e*b0M" ); // 4. start raster graphics at current cursor position fprintf( prn, "\e*r1A" ); // 5. transfer raster data row-by-row for (int row = 0; row < BANDWIDTH; row++) { unsigned char raster[ 256 ] = {0}; unsigned char *band; for (int b = 0; b < BANDS_PER_PAGE; b++) { int dst = 64*(BANDS_PER_PAGE - 1 - b); int src = b * BANDWIDTH + row; band = (unsigned char*)( vimage + src ); if ( src < chunk_size ) for (int y = 0; y < 0x40; y++) raster[ dst + y ] = band[ y ]; } fprintf( prn, "\e*b%dW", sizeof( raster ) ); fwrite( raster, sizeof( raster ), 1, prn ); } // 6. end raster graphics fprintf( prn, "\e*rB" ); // 7. output the page legend fprintf( prn, "\e*p%dY\e*p%dX", 0, 0 ); fprintf( prn, "\e*p%dY\e*p%dX", 150, 2250 ); fprintf( prn, "\e&a%dP", 270 ); // font rotation: -90 degrees fprintf( prn, "Filename: %-26s ", wavename ); double band_duration = (double)BANDWIDTH / (double)samplesPerSec; band_duration *= 1000.0; fprintf( prn, "band-duration: %0.2f milliseconds ", band_duration ); fprintf( prn, "sample-rate: %d Hz ", samplesPerSec ); fprintf( prn, "(%d-bit samples) ", bitsPerSample ); // eject page fprintf( prn, "\f" ); fclose( prn ); free( vimage ); free( wavdata ); // use 'lpr' command to submit the temporary file for printing char command[ 128 ] = {0}; int len = sprintf( command, "lpr %s ", tempname ); for (int i = 2; i < argc; i++) len += sprintf( command+len, "%s ", argv[i] ); system( command ); unlink( tempname ); fprintf( stderr, "\n\n" ); }