00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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;
00033 u_long length;
00034 u_long chunk_type;
00035 u_long sub_chunk;
00036 u_long sc_len;
00037
00038 u_short format;
00039
00040 u_short modus;
00041 u_long sample_fq;
00042 u_long byte_p_sec;
00043 u_short byte_p_spl;
00044 u_short bit_p_spl;
00045
00046 u_long data_chunk;
00047
00048 u_long data_length;
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
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
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
00229
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 * ) {
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
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
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
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
00386
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;
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);
00407 channels=1;
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
00430 }
00431 if(ioctl(dsp, SNDCTL_DSP_CHANNELS , &channels)==-1) {
00432 perror("ioctl(\"SNDCTL_DSP_CHANNELS\")");
00433
00434 }
00435 if(ioctl(dsp, SNDCTL_DSP_SPEED , &speed)==-1) {
00436 perror("ioctl(\"SNDCTL_DSP_SPEED\")");
00437
00438 }
00439 if(ioctl(dsp, SOUND_PCM_READ_RATE , &rate)==-1) {
00440 perror("ioctl(\"SOUND_PCM_READ_RATE\")");
00441
00442 }
00443
00444 QCopEnvelope( "QPE/System", "volumeChange(bool)" ) << false;
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;
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
00480
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];
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);
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);
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);
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);
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
00566
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
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;
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;
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
00656 stopRecording();
00657 QMessageBox::message("Vmemo","Vmemo recording has ended");
00658 }
00659
00660
00661 EXPORT_OPIE_APPLET_v1( VMemo )
00662