Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

vmemo.cpp

Go to the documentation of this file.
00001 /************************************************************************************
00002  **
00003  ** This file may be distributed and/or modified under the terms of the
00004  ** GNU General Public License version 2 as published by the Free Software
00005  ** Foundation and appearing in the file LICENSE.GPL included in the
00006  ** packaging of this file.
00007  **
00008  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00009  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00010  **
00011  ************************************************************************************/
00012 // copyright 2002 Jeremy Cowgar <jc@cowgar.com>
00013 // copyright 2002 and 2003  L.J.Potter <ljp@llornkcor.com>
00014 
00015 /* OPIE */
00016 #include <opie2/odebug.h>
00017 using namespace Opie::Core;
00018 
00019 extern "C" {
00020 #include "adpcm.h"
00021 }
00022 
00023 #include <unistd.h>
00024 #include <stdio.h>
00025 #include <fcntl.h>
00026 #include <sys/ioctl.h>
00027 #include <linux/soundcard.h>
00028 
00029 #include <errno.h>
00030 
00031 typedef struct _waveheader {
00032   u_long  main_chunk; /* 'RIFF'  */
00033   u_long  length;     /* filelen */
00034   u_long  chunk_type; /* 'WAVE'  */
00035   u_long  sub_chunk;  /* 'fmt '                                               */
00036   u_long  sc_len;     /* length of sub_chunk, =16
00037                          (chunckSize) format len */
00038   u_short format;     /* should be 1 for PCM-code        (formatTag)          */
00039 
00040   u_short modus;      /* 1 Mono, 2 Stereo                (channels)           */
00041   u_long  sample_fq;  /* samples per second              (samplesPerSecond)   */
00042   u_long  byte_p_sec; /* avg bytes per second            (avgBytePerSecond)   */
00043   u_short byte_p_spl; /* samplesize; 1 or 2 bytes        (blockAlign)         */
00044   u_short bit_p_spl;  /* 8, 12 or 16 bit                 (bitsPerSample)      */
00045 
00046   u_long  data_chunk; /* 'data'      */
00047 
00048   u_long  data_length;/* samplecount */
00049 } WaveHeader;
00050 
00051 #define RIFF        0x46464952
00052 #define WAVE        0x45564157
00053 #define FMT         0x20746D66
00054 #define DATA        0x61746164
00055 #define PCM_CODE    1
00056 #define WAVE_MONO   1
00057 #define WAVE_STEREO 2
00058 
00059 struct adpcm_state encoder_state;
00060 //struct adpcm_state decoder_state;
00061 
00062 #define WAVE_FORMAT_DVI_ADPCM (0x0011)
00063 #define WAVE_FORMAT_PCM (0x0001)
00064 
00065 
00066 #include "vmemo.h"
00067 
00068 #include <opie2/otaskbarapplet.h>
00069 #include <qpe/qpeapplication.h>
00070 #include <qpe/config.h>
00071 
00072 #include <qpainter.h>
00073 #include <qmessagebox.h>
00074 
00075 int seq = 0;
00076 
00077 /* XPM */
00078 static char * vmemo_xpm[] = {
00079   "16 16 102 2",
00080   "   c None",
00081   ".  c #60636A",
00082   "+  c #6E6E72",
00083   "@  c #68696E",
00084   "#  c #4D525C",
00085   "$  c #6B6C70",
00086   "%  c #E3E3E8",
00087   "&  c #EEEEF2",
00088   "*  c #EAEAEF",
00089   "=  c #CACAD0",
00090   "-  c #474A51",
00091   ";  c #171819",
00092   ">  c #9B9B9F",
00093   ",  c #EBEBF0",
00094   "'  c #F4F4F7",
00095   ")  c #F1F1F5",
00096   "!  c #DEDEE4",
00097   "~  c #57575C",
00098   "{  c #010101",
00099   "]  c #A2A2A6",
00100   "^  c #747477",
00101   "/  c #B5B5B8",
00102   "(  c #AEAEB2",
00103   "_  c #69696D",
00104   ":  c #525256",
00105   "<  c #181C24",
00106   "[  c #97979B",
00107   "}  c #A7A7AC",
00108   "|  c #B0B0B4",
00109   "1  c #C8C8D1",
00110   "2  c #75757B",
00111   "3  c #46464A",
00112   "4  c #494A4F",
00113   "5  c #323234",
00114   "6  c #909095",
00115   "7  c #39393B",
00116   "8  c #757578",
00117   "9  c #87878E",
00118   "0  c #222224",
00119   "a  c #414144",
00120   "b  c #6A6A6E",
00121   "c  c #020C16",
00122   "d  c #6B6B6F",
00123   "e  c #68686D",
00124   "f  c #5B5B60",
00125   "g  c #8A8A8F",
00126   "h  c #6B6B6E",
00127   "i  c #ADADB2",
00128   "j  c #828289",
00129   "k  c #3E3E41",
00130   "l  c #CFCFD7",
00131   "m  c #4C4C50",
00132   "n  c #000000",
00133   "o  c #66666A",
00134   "p  c #505054",
00135   "q  c #838388",
00136   "r  c #A1A1A7",
00137   "s  c #A9A9AE",
00138   "t  c #A8A8B0",
00139   "u  c #5E5E63",
00140   "v  c #3A3A3E",
00141   "w  c #BDBDC6",
00142   "x  c #59595E",
00143   "y  c #76767C",
00144   "z  c #373738",
00145   "A  c #717174",
00146   "B  c #727278",
00147   "C  c #1C1C1E",
00148   "D  c #3C3C3F",
00149   "E  c #ADADB6",
00150   "F  c #54555A",
00151   "G  c #8B8C94",
00152   "H  c #5A5A5F",
00153   "I  c #BBBBC3",
00154   "J  c #C4C4CB",
00155   "K  c #909098",
00156   "L  c #737379",
00157   "M  c #343437",
00158   "N  c #8F8F98",
00159   "O  c #000407",
00160   "P  c #2D3137",
00161   "Q  c #B0B1BC",
00162   "R  c #3B3C40",
00163   "S  c #6E6E74",
00164   "T  c #95959C",
00165   "U  c #74747A",
00166   "V  c #1D1D1E",
00167   "W  c #91929A",
00168   "X  c #42444A",
00169   "Y  c #22282E",
00170   "Z  c #B0B2BC",
00171   "`  c #898A90",
00172   " . c #65656A",
00173   ".. c #999AA2",
00174   "+. c #52535A",
00175   "@. c #151B21",
00176   "#. c #515257",
00177   "$. c #B5B5BE",
00178   "%. c #616167",
00179   "&. c #1A1D22",
00180   "*. c #000713",
00181   "=. c #1F1F21",
00182   "                                ",
00183   "            . + @ #             ",
00184   "          $ % & * = -           ",
00185   "        ; > , ' ) ! ~           ",
00186   "        { ] ^ / ( _ :           ",
00187   "        < [ } | 1 2 3           ",
00188   "      4 5 6 7 8 9 0 a b c       ",
00189   "    d e f g h i j 3 k l m n     ",
00190   "      o p q r s t u v w n       ",
00191   "      o x y z A B C D E n       ",
00192   "      F G H I J K L M N O       ",
00193   "      P Q R S T U V W X         ",
00194   "        Y Z ` b  ...+.          ",
00195   "          @.#.$.%.&.            ",
00196   "            *.B =.              ",
00197   "      n n n n n n n n n         "};
00198 
00199 
00200 using namespace Opie::Ui;
00201 VMemo::VMemo( QWidget *parent, const char *_name )
00202   : QWidget( parent, _name ) {
00203   setFixedHeight( 18 );
00204   setFixedWidth( 14 );
00205 
00206   t_timer = new QTimer( this );
00207   connect( t_timer, SIGNAL( timeout() ), SLOT( timerBreak() ) );
00208 
00209     Config vmCfg("Vmemo");
00210     vmCfg.setGroup("Defaults");
00211     int toggleKey = setToggleButton(vmCfg.readNumEntry("toggleKey", -1));
00212     useADPCM = vmCfg.readBoolEntry("use_ADPCM", 0);
00213 
00214     owarn <<"VMemo toggleKey" << toggleKey << oendl;
00215 
00216       systemZaurus = false;
00217 
00218     myChannel = new QCopChannel( "QPE/VMemo", this );
00219 
00220     connect( myChannel, SIGNAL(received(const QCString&,const QByteArray&)),
00221              this, SLOT(receive(const QCString&,const QByteArray&)) );
00222 
00223 
00224     if( toggleKey != -1 ) {
00225                                 owarn << "Register key " << toggleKey << "" << oendl;
00226 
00227                                 QCopEnvelope e("QPE/Launcher", "keyRegister(int,QCString,QCString)");
00228       //           e << 4096; // Key_Escape
00229       //          e << Key_F5; //4148
00230       e << toggleKey;
00231       e << QCString("QPE/VMemo");
00232       e << QCString("toggleRecord()");
00233     }
00234     if(toggleKey == 0)
00235         usingIcon = true;
00236     else
00237         usingIcon = false;
00238         if (!usingIcon)
00239                         hide();
00240     recording = false;
00241 }
00242 
00243 VMemo::~VMemo() {
00244 }
00245 
00246 int VMemo::position()
00247 {
00248     return 1;
00249 }
00250 
00251 void VMemo::receive( const QCString &msg, const QByteArray &data ) {
00252   QDataStream stream( data, IO_ReadOnly );
00253 
00254   if (msg == "toggleRecord()")  {
00255       if (recording) {
00256           fromToggle = true;
00257           stopRecording();
00258       }  else {
00259           fromToggle = true;
00260           startRecording();
00261       }
00262   }
00263 }
00264 
00265 void VMemo::paintEvent( QPaintEvent* ) {
00266   QPainter p(this);
00267   p.drawPixmap( 0, 1,( const char** )  vmemo_xpm );
00268 }
00269 
00270 void VMemo::mousePressEvent( QMouseEvent * /*me*/) {
00271 
00272                 if(!recording) {
00273                                 if(!startRecording() ){
00274                                                 QMessageBox::critical(0, "vmemo", "Abort Recording", "Abort Recording");
00275                                 }
00276                 }   else {
00277                                 stopRecording();
00278                 }
00279 }
00280 
00281 void VMemo::mouseReleaseEvent( QMouseEvent * ) {
00282 }
00283 
00284 bool VMemo::startRecording() {
00285   Config config( "Vmemo" );
00286   config.setGroup( "System" );
00287 
00288 
00289   odebug << "Start recording engines" << oendl;
00290   recording = true;
00291 
00292   if (openDSP() == -1)  {
00293                         recording = false;
00294                         return false;
00295   }
00296 
00297   config.setGroup("Defaults");
00298 
00299   date = TimeString::dateString( QDateTime::currentDateTime(),false,true);
00300   date.replace(QRegExp("'"),"");
00301   date.replace(QRegExp(" "),"_");
00302   date.replace(QRegExp(":"),"-");
00303   date.replace(QRegExp(","),"");
00304 
00305   QString fName;
00306   config.setGroup( "System" );
00307   fName = QPEApplication::documentDir() ;
00308   fileName = config.readEntry("RecLocation", fName);
00309 
00310   int s;
00311   s=fileName.find(':');
00312   if(s)
00313     fileName=fileName.right(fileName.length()-s-2);
00314   odebug << "pathname will be "+fileName << oendl;
00315 
00316   if( fileName.left(1).find('/') == -1)
00317     fileName="/"+fileName;
00318   if( fileName.right(1).find('/') == -1)
00319     fileName+="/";
00320   fName = "vm_"+ date + ".wav";
00321 
00322   fileName += fName;
00323   odebug << "filename is " + fileName << oendl;
00324 
00325   useAlerts = config.readBoolEntry("Alert",1);
00326   if(useAlerts) {
00327     msgLabel = new QLabel( 0, "alertLabel" );
00328     msgLabel->setText( tr("<B><P><font size=+2>VMemo-Recording</font></B><p>%1</p>").arg("vm_"+ date));
00329     msgLabel->show();
00330   }
00331         
00332 // open tmp file here
00333   char *pointer;
00334   pointer=tmpnam(NULL);
00335   odebug << "Opening tmp file " << pointer << "" << oendl;
00336 
00337   if(openWAV(pointer ) == -1)  {
00338 
00339     QString err("Could not open the temp file\n");
00340     err += fileName;
00341     QMessageBox::critical(0, "vmemo", err, "Abort");
00342     ::close(dsp);
00343     return false;
00344   }
00345   if( record() ) {
00346 
00347   QString cmd;
00348   if( fileName.find(".wav",0,true) == -1)
00349       fileName += ".wav";
00350 
00351   cmd.sprintf("mv %s "+fileName, pointer);
00352 // move tmp file to regular file here
00353 
00354   system(cmd.latin1());
00355 
00356   QArray<int> cats(1);
00357   cats[0] = config.readNumEntry("Category", 0);
00358 
00359   QString dlName("vm_");
00360   dlName += date;
00361   DocLnk l;
00362   l.setFile(fileName);
00363   l.setName(dlName);
00364   l.setType("audio/x-wav");
00365   l.setCategories(cats);
00366   l.writeLink();
00367   return true;
00368   } else
00369       return false;
00370 
00371 }
00372 
00373 void VMemo::stopRecording() {
00374 //    show();
00375     odebug << "Stopped recording" << oendl;
00376     recording = false;
00377     if(useAlerts) {
00378         msgLabel->close();
00379         msgLabel=0;
00380         delete msgLabel;
00381     }
00382     t_timer->stop();
00383     Config cfg("Vmemo");
00384     cfg.setGroup("Defaults");
00385 //     if( cfg.readNumEntry("hideIcon",0) == 1 )
00386 //         hide();
00387 }
00388 
00389 int VMemo::openDSP() {
00390   Config cfg("Vmemo");
00391   cfg.setGroup("Record");
00392 
00393   speed = cfg.readNumEntry("SampleRate", 22050);
00394   channels = cfg.readNumEntry("Stereo", 1) ? 2 : 1; // 1 = stereo(2), 0 = mono(1)
00395   if (cfg.readNumEntry("SixteenBit", 1)==1)  {
00396     format = AFMT_S16_LE;
00397     resolution = 16;
00398   } else {
00399     format = AFMT_U8;
00400     resolution = 8;
00401   }
00402 
00403   odebug << "samplerate: " << speed << ", channels " << channels << ", resolution " << resolution << "" << oendl;
00404 
00405   if(systemZaurus) {
00406     dsp = open("/dev/dsp1", O_RDONLY); //Zaurus needs /dev/dsp1
00407     channels=1; //zaurus has one input channel
00408   }  else {
00409 #ifdef QT_QWS_DEVFS
00410     dsp = open("/dev/sound/dsp", O_RDONLY);
00411 #else
00412     dsp = open("/dev/dsp", O_RDONLY);
00413 #endif
00414   }
00415 
00416   if (dsp == -1)  {
00417       msgLabel->close();
00418       msgLabel=0;
00419       delete msgLabel;
00420 
00421       perror("open(\"/dev/dsp\")");
00422       errorMsg="open(\"/dev/dsp\")\n "+(QString)strerror(errno);
00423       QMessageBox::critical(0, "vmemo", errorMsg, "Abort");
00424       return -1;
00425   }
00426 
00427   if(ioctl(dsp, SNDCTL_DSP_SETFMT , &format)==-1)  {
00428     perror("ioctl(\"SNDCTL_DSP_SETFMT\")");
00429 //    return -1;
00430   }
00431   if(ioctl(dsp, SNDCTL_DSP_CHANNELS , &channels)==-1)  {
00432     perror("ioctl(\"SNDCTL_DSP_CHANNELS\")");
00433 //    return -1;
00434   }
00435   if(ioctl(dsp, SNDCTL_DSP_SPEED , &speed)==-1)  {
00436     perror("ioctl(\"SNDCTL_DSP_SPEED\")");
00437 //    return -1;
00438   }
00439   if(ioctl(dsp, SOUND_PCM_READ_RATE , &rate)==-1)  {
00440     perror("ioctl(\"SOUND_PCM_READ_RATE\")");
00441 //    return -1;
00442   }
00443 
00444   QCopEnvelope( "QPE/System", "volumeChange(bool)" ) << false; //mute
00445 
00446   return 1;
00447 }
00448 
00449 int VMemo::openWAV(const char *filename) {
00450   track.setName(filename);
00451   if(!track.open(IO_WriteOnly|IO_Truncate|IO_Raw)) {
00452     errorMsg=filename;
00453     return -1;
00454   }
00455 
00456   wav=track.handle();
00457     Config vmCfg("Vmemo");
00458     vmCfg.setGroup("Defaults");
00459   useADPCM = vmCfg.readBoolEntry("use_ADPCM", 0);
00460 
00461   WaveHeader wh;
00462 
00463   wh.main_chunk = RIFF;
00464   wh.length=0;
00465   wh.chunk_type = WAVE;
00466   wh.sub_chunk  = FMT;
00467   wh.sc_len     = 16;
00468   if(useADPCM)
00469       wh.format     = WAVE_FORMAT_DVI_ADPCM;//PCM_CODE;
00470   else
00471       wh.format     = PCM_CODE;
00472   wh.modus      = channels;
00473   wh.sample_fq  = speed;
00474   wh.byte_p_sec = speed * channels *  resolution/8;
00475   wh.byte_p_spl = channels * (resolution / 8);
00476   wh.bit_p_spl  = resolution;
00477   wh.data_chunk = DATA;
00478   wh.data_length= 0;
00479   //    odebug << "Write header channels " << wh.modus << ", speed " << wh.sample_fq << ", b/s "
00480   //           << wh.byte_p_sec << ", blockalign " << wh.byte_p_spl << ", bitrate " << wh.bit_p_spl << oendl;
00481   write (wav, &wh, sizeof(WaveHeader));
00482 
00483   return 1;
00484 }
00485 
00486 bool VMemo::record() {
00487                 length = 0;
00488                 int bytesWritten = 0;
00489                 int result = 0;
00490                 int value = 0;
00491 
00492                 QString msg;
00493                 msg.sprintf("Recording format %d", format);
00494                 odebug << msg << oendl;
00495 
00496                 Config config("Vmemo");
00497                 config.setGroup("Record");
00498                 int sRate = config.readNumEntry("SizeLimit", 30);
00499                 odebug << "VMEMO rate" << sRate << oendl;
00500 
00501                 if(sRate > 0) {
00502                                 t_timer->start( sRate * 1000+1000, true);
00503                 }
00504 
00505                 msg.sprintf("Recording format other");
00506                 odebug << msg << oendl;
00507 
00508     config.setGroup("Defaults");
00509     useADPCM = config.readBoolEntry("use_ADPCM", 0);
00510 
00511     int bufsize = config.readNumEntry("BufferSize",1024);
00512     unsigned short sound[bufsize]; //, monoBuffer[bufsize];
00513     char abuf[bufsize / 2];
00514     short sbuf[bufsize];
00515                 odebug << "ready to record"<< oendl;
00516                 if(useADPCM) {
00517                                 odebug << "usr ADPCM" << oendl;
00518 
00519                                 while(recording) {
00520                                                 result = ::read(dsp, sbuf, bufsize); // adpcm read
00521                                                 if( result <= 0) {
00522                                                                 perror("recording error ");
00523                                                                 QMessageBox::message(tr("Note"),tr("error recording"));
00524                                                                 recording = false;
00525                                                                 break;
00526                                                                 return false;
00527                                                 }
00528                                                 adpcm_coder( sbuf, abuf, result/2, &encoder_state);
00529                                                 bytesWritten = ::write(wav, abuf, result/4); // adpcm write
00530                                                 length += bytesWritten;
00531 
00532                                                 if(length < 0) {
00533                                                                 recording = false;
00534                                                                 perror("dev/dsp's is a lookin' messy");
00535                                                                 QMessageBox::message("Vmemo","Error writing to file\n"+ fileName);
00536                                                                 break;
00537                                                                 return false;
00538                                                 }
00539                                                 printf("%d\r", length);
00540                                                 fflush(stdout);
00541                                                 qApp->processEvents();
00542                                 }
00543                 } else {
00544                                 odebug << "use regular wav" << oendl;
00545                                 while(recording) {
00546                                                 result = ::read(dsp, sound, bufsize); // read
00547                                                 if( result <= 0) {
00548                                                                 perror("recording error ");
00549                                                                 QMessageBox::message(tr("Note"),tr("error recording"));
00550                                                                 recording = false;
00551                                                                 break;
00552                                                                 return false;
00553                                                 }
00554 
00555                                                 bytesWritten = ::write(wav, sound, result); // write
00556                                                 length += bytesWritten;
00557 
00558                                                 if(length < 0) {
00559                                                                 recording = false;
00560                                                                 perror("dev/dsp's is a lookin' messy");
00561                                                                 QMessageBox::message("Vmemo","Error writing to file\n"+ fileName);
00562                                                                 break;
00563                                                                 return false;
00564                                                 }
00565 //          printf("%d\r", length);
00566 //          fflush(stdout);
00567                                                 qApp->processEvents();
00568                                 }
00569                 }
00570                 owarn << "file has length of " << length << " lasting " << (( length / speed) / channels) / 2  << " seconds" << oendl;
00571 
00572                 value = length + 36;
00573 
00574                 lseek(wav, 4, SEEK_SET);
00575                 write(wav, &value, 4);
00576                 lseek(wav, 40, SEEK_SET);
00577 
00578                 write(wav, &length, 4);
00579 
00580                 track.close();
00581 
00582                 if( ioctl( dsp, SNDCTL_DSP_RESET,0) == -1)
00583                                 perror("ioctl(\"SNDCTL_DSP_RESET\")");
00584 
00585                 ::close(dsp);
00586 
00587                 Config cfgO("OpieRec");
00588                 cfgO.setGroup("Sounds");
00589 
00590                 int nFiles = cfgO.readNumEntry( "NumberofFiles",0);
00591 
00592                 QString currentFileName = fileName;
00593                 QString currentFile = "vm_"+ date;
00594 
00595                 float numberOfRecordedSeconds = (float) length / (float)speed * (float)2;
00596 
00597                 cfgO.writeEntry( "NumberofFiles", nFiles + 1);
00598                 cfgO.writeEntry( QString::number( nFiles + 1), currentFile);
00599                 cfgO.writeEntry( currentFile, currentFileName);
00600 
00601                 QString time;
00602                 time.sprintf("%.2f", numberOfRecordedSeconds);
00603                 cfgO.writeEntry( currentFileName, time );
00604       //      odebug << "writing config numberOfRecordedSeconds "+time << oendl;
00605 
00606                 cfgO.write();
00607 
00608                 odebug << "done recording "+fileName << oendl;
00609 
00610                 Config cfg("qpe");
00611                 cfg.setGroup("Volume");
00612                 QString foo = cfg.readEntry("Mute","true");
00613                 if(foo.find("true",0,true) != -1)
00614                                 QCopEnvelope( "QPE/System", "volumeChange(bool)" ) << true; //mute
00615                 return true;
00616 }
00617 
00618 int VMemo::setToggleButton(int tog) {
00619 
00620   for( int i=0; i < 10;i++) {
00621     switch (tog) {
00622     case 0:
00623       return -1;
00624       break;
00625     case 1:
00626       return 0;
00627       break;
00628     case 2:
00629         return Key_F24; //was Escape
00630       break;
00631     case 3:
00632       return Key_Space;
00633       break;
00634     case 4:
00635       return Key_F12;
00636       break;
00637     case 5:
00638       return Key_F9;
00639       break;
00640     case 6:
00641       return Key_F10;
00642       break;
00643     case 7:
00644       return Key_F11;
00645       break;
00646     case 8:
00647       return Key_F13;
00648       break;
00649     };
00650   }
00651   return -1;
00652 }
00653 
00654 void VMemo::timerBreak() {
00655   //stop
00656     stopRecording();
00657   QMessageBox::message("Vmemo","Vmemo recording has ended");
00658 }
00659 
00660 
00661 EXPORT_OPIE_APPLET_v1( VMemo )
00662 

Generated on Sat Nov 5 16:15:24 2005 for OPIE by  doxygen 1.4.2