{"id":244,"date":"2010-09-10T14:51:22","date_gmt":"2010-09-10T20:51:22","guid":{"rendered":"http:\/\/www.goodjobsucking.com\/?p=244"},"modified":"2010-09-10T14:51:22","modified_gmt":"2010-09-10T20:51:22","slug":"voice-announcements-via-modem","status":"publish","type":"post","link":"http:\/\/www.goodjobsucking.com\/?p=244","title":{"rendered":"Voice Announcements via Modem"},"content":{"rendered":"<p>We have a PBX system through which it&#8217;s possible to make announcements, some of which I find myself making regularly.\u00a0 Having an old voice modem lying about, I decided to program it to make regular announcements for me.<\/p>\n<p>Rather than dedicate a modem to voice announcements, I decided to share a modem that&#8217;s also used for <a href=\"http:\/\/www.hylafax.org\/\">HylaFAX<\/a>, on the principle that the less hardware to have to worry about, the better.\u00a0 HylaFAX shares a locking system with <a href=\"http:\/\/alioth.debian.org\/projects\/minicom\/\">minicom<\/a>, meaning that if I use minicom for the voice announcements, I don&#8217;t have to worry about who has control of the modem, or of relinquishing control to HylaFAX.<\/p>\n<p>I located an ancient <a href=\"http:\/\/www.usrmodem.ru\/files\/voicecmd.pdf\">voice command\u00a0 manual for my US Robotics voice modem<\/a> online.\u00a0 While it took some trial-and-error, I eventually whanged together this script:<\/p>\n<pre>#\/bin\/bash\r\nif [ \"$1\" = \"--help\" ] || [ \"$1\" = \"\" ] || [ \"$2\" = \"\" ]; then\r\necho 1&gt;&amp;2 Usage: $0 [# to dial] [voicefile.rmd]\r\necho --help\u00a0\u00a0\u00a0\u00a0\u00a0 this message\r\nexit 1\r\nfi\r\nPID=$$\r\ncd \/tmp\r\necho print \"starting\" &gt; \/tmp\/minicom.$PID\r\necho send \"ATZ\" &gt;&gt; \/tmp\/minicom.$PID\r\necho expect { &gt;&gt; \/tmp\/minicom.$PID\r\necho \\\"OK\\\" &gt;&gt; \/tmp\/minicom.$PID\r\necho } &gt;&gt; \/tmp\/minicom.$PID\r\necho send \"AT#CLS=8\" &gt;&gt; \/tmp\/minicom.$PID\r\necho expect { &gt;&gt; \/tmp\/minicom.$PID\r\necho \\\"OK\\\" &gt;&gt; \/tmp\/minicom.$PID\r\necho } &gt;&gt; \/tmp\/minicom.$PID\r\necho send \"AT#VRN=0\" &gt;&gt; \/tmp\/minicom.$PID\r\necho expect { &gt;&gt; \/tmp\/minicom.$PID\r\necho \\\"OK\\\" &gt;&gt; \/tmp\/minicom.$PID\r\necho } &gt;&gt; \/tmp\/minicom.$PID\r\necho send \"AT#VRA=0\" &gt;&gt; \/tmp\/minicom.$PID\r\necho expect { &gt;&gt; \/tmp\/minicom.$PID\r\necho \\\"OK\\\" &gt;&gt; \/tmp\/minicom.$PID\r\necho } &gt;&gt; \/tmp\/minicom.$PID\r\necho send \"AT#VSM=129,8000\" &gt;&gt; \/tmp\/minicom.$PID\r\necho expect { &gt;&gt; \/tmp\/minicom.$PID\r\necho \\\"OK\\\" &gt;&gt; \/tmp\/minicom.$PID\r\necho } &gt;&gt; \/tmp\/minicom.$PID\r\necho send \"ATS46=255\" &gt;&gt; \/tmp\/minicom.$PID\r\necho expect { &gt;&gt; \/tmp\/minicom.$PID\r\necho \\\"OK\\\" &gt;&gt; \/tmp\/minicom.$PID\r\necho } &gt;&gt; \/tmp\/minicom.$PID\r\necho send \"AT#VRA=0\" &gt;&gt; \/tmp\/minicom.$PID\r\necho expect { &gt;&gt; \/tmp\/minicom.$PID\r\necho \\\"OK\\\" &gt;&gt; \/tmp\/minicom.$PID\r\necho } &gt;&gt; \/tmp\/minicom.$PID\r\necho send \"ATDT,$1\" &gt;&gt; \/tmp\/minicom.$PID\r\necho expect { &gt;&gt; \/tmp\/minicom.$PID\r\necho \\\"VCON\\\" &gt;&gt; \/tmp\/minicom.$PID\r\necho } &gt;&gt; \/tmp\/minicom.$PID\r\necho \"sleep 1\" &gt;&gt; \/tmp\/minicom.$PID\r\n# here's the voice part\r\necho send \"AT#VTX\" &gt;&gt; \/tmp\/minicom.$PID\r\necho expect { &gt;&gt; \/tmp\/minicom.$PID\r\necho \\\"CONNECT\\\" &gt;&gt; \/tmp\/minicom.$PID\r\necho } &gt;&gt; \/tmp\/minicom.$PID\r\necho \"sleep 1\" &gt;&gt; \/tmp\/minicom.$PID\r\necho \"! cp $2 \/dev\/ttyUSB0\" &gt;&gt; \/tmp\/minicom.$PID\r\n# end\r\necho &gt;&gt; \/tmp\/minicom.$PID\r\necho sleep 2 &gt;&gt; \/tmp\/minicom.$PID\r\necho ! killall minicom &gt;&gt; \/tmp\/minicom.$PID\r\n\/usr\/bin\/minicom -S \/tmp\/minicom.$PID\r\ncat \/tmp\/minicom.$PID\r\nrm \/tmp\/minicom.$PID<\/pre>\n<p>It&#8217;s fairly linear &#8212; it puts the modem into voice mode, sets a number of parameters, and escapes to the shell to copy a file to the device.\u00a0 What remained is to create a file in a format that the modem could consume.<\/p>\n<p>Luckily, Ubuntu has a package called <a href=\"http:\/\/packages.ubuntu.com\/hardy\/mgetty-pvftools\">mgetty-pvftools<\/a> which contains all the binary files necessary to make it happen.\u00a0 (These files are bundled with vgetty on Gentoo, but vgetty conflicts with HylaFAX, and all I need are the audio conversion binaries.)<\/p>\n<p>It&#8217;s several steps to convert, but this script does it handily:<\/p>\n<pre>#!\/bin\/bash\r\nPID=$$\r\nif [ \"$1\" = \"--help\" ] || [ \"$1\" = \"\" ] || [ \"$2\" = \"\" ]; then\r\necho 1&gt;&amp;2 Usage: $0 [from.mp3] [to.rmd]\r\necho --help\u00a0\u00a0\u00a0\u00a0\u00a0 this message\r\nexit 1\r\nfi\r\necho \"mp3-&gt;wav\"\r\nsox -V --norm $1 -r 8k -c 1 \/tmp\/$PID.wav\r\necho \"wav-&gt;pvf\"\r\nwavtopvf \/tmp\/$PID.wav \/tmp\/$PID.pvf\r\necho \"pvf-&gt;rmd\"\r\npvftormd US_Robotics 4 \/tmp\/$PID.pvf $2\r\nrm \/tmp\/$PID.wav\r\nrm \/tmp\/$PID.pvf<\/pre>\n<p>So, all that&#8217;s left to do is to set up the first script in an &#8220;at&#8221; or &#8220;cron&#8221; job.\u00a0 However, it turns out that minicom requires an interactive terminal to run, so simply running the first script from an &#8220;at&#8221; job resulted in this error:<\/p>\n<pre>No cursor motion capability (cm)<\/pre>\n<p>Since the script will run minicom without being attended, a simple way around this is to use the &#8220;screen&#8221; program to provide an interactive terminal for minicom to use within cron\/at:<\/p>\n<pre>screen -d -m announce.sh 111 announcefile.rmd<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>We have a PBX system through which it&#8217;s possible to make announcements, some of which I find myself making regularly.\u00a0 Having an old voice modem lying about, I decided to program it to make regular announcements for me. Rather than dedicate a modem to voice announcements, I decided to share \u2026 <a class=\"continue-reading-link\" href=\"http:\/\/www.goodjobsucking.com\/?p=244\"> Continue reading <span class=\"meta-nav\">&rarr; <\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[126,124,125],"_links":{"self":[{"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=\/wp\/v2\/posts\/244"}],"collection":[{"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=244"}],"version-history":[{"count":2,"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=\/wp\/v2\/posts\/244\/revisions"}],"predecessor-version":[{"id":246,"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=\/wp\/v2\/posts\/244\/revisions\/246"}],"wp:attachment":[{"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=244"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=244"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodjobsucking.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=244"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}