PHP實現基於文本的莫斯電碼產生器_PHP教程

來源:互聯網
上載者:User

PHP實現基於文本的莫斯電碼產生器


介紹

我最近遇到一個基於輸入文本產生摩斯代碼音頻檔案的需求。幾番搜尋無果之後,我決定自己編寫一個產生器。

下載原始碼 – 2.63 KB

因為我希望通過web的方式訪問我的摩斯代碼音頻檔案,所以我決定採用PHP作為我主要的程式設計語言。上面的顯示了一個開始產生莫斯代碼的網頁。 在下載的zip檔案中,包含了用於提交文本的網頁以及用於產生和展現音頻檔案的PHP源檔案。如果你想測試PHP代碼,你需要將網頁和相關的PHP檔案複 制到啟用了PHP的伺服器上。

對於許多人來說,莫斯代碼就像一些老電影中表現的那樣,就是一些“點”和“橫線”的序列,或者一連串的嗶嗶聲。顯然,如果你想用電腦代碼來產生莫 斯代碼,這樣的瞭解是遠遠不夠的。這篇文章將會介紹產生莫斯代碼的要素,如何產生WAVE 格式的音頻檔案,以及如何用PHP將莫斯代碼轉化成音頻檔案。

莫斯代碼

莫斯代碼是一種文本編碼方式。它的優點是編碼方便,而且用人耳就能夠方便的解碼。本質上,是通過音頻或者無線電頻)的開和關,從而形成或短或長的 音頻脈衝,一般稱作點dot)和線dash),或者用無線電術語稱作“嘀”和“嗒”。用現代數字通訊術語,莫斯代碼是一種振幅鍵控 amplitude shift keying ,ASK)。

在莫斯代碼中,字元字母,數字,標點符號和特殊符號)被編碼成一個“嘀”和“嗒”的序列。所以為了把文本轉化成莫斯代碼,我們首先要確定如何來表 示“嘀”和“嗒”。一個很顯然的選擇就是,用0表示“嘀”,用1表示“嗒”,或者反過來。不幸的是,莫斯代碼採用的是可變長編碼方案。所以我們也必須要使 用一種可變長序列,或者採取一種方式,把資料打包成一種電腦記憶體通用的固定位寬fixed bit-size)的格式。另外,需要特別注意的是,莫斯代碼並不區分字母大小寫,而且對一些特殊符號無法編碼。在我們這個實現中,未定義的字元和符號將 會被忽略。

在這個項目中,記憶體佔用並不是一個需要特別考慮的問題。所以,我們提出一個簡單的編碼方案,即用“0”來表示每個“嘀”,用“1”來表示每個“嗒”,並且把他們放在一個字串關聯陣列中。定義莫斯代碼編碼錶的PHP代碼就像下面這樣:

 
  1. $CWCODE = array ('A'=>'01','B'=>'1000','C'=>'1010','D'=>'100','E'=>'0',
  2. 'F'=>'0010','G'=>'110','H'=>'0000','I'=>'00','J'=>'0111',
  3. 'K'=>'101','L'=>'0100','M'=>'11','N'=>'10', 'O'=>'111',
  4. 'P'=>'0110','Q'=>'1101','R'=>'010','S'=>'000','T'=>'1',
  5. 'U'=>'001','V'=>'0001','W'=>'011','X'=>'1001','Y'=>'1011',
  6. 'Z'=>'1100', '0'=>'11111','1'=>'01111','2'=>'00111',
  7. '3'=>'00011','4'=>'00001','5'=>'00000','6'=>'10000',
  8. '7'=>'11000','8'=>'11100','9'=>'11110','.'=>'010101',
  9. ','=>'110011','/'=>'10010','-'=>'10001','~'=>'01010',
  10. '?'=>'001100','@'=>'00101');

需要注意的是,如果你特別在意記憶體佔用的話,上面的代碼可以解釋為位bit)。給每個代碼增加一個開始位,就可以形成一個位的模式,每個字元就可以用一個位元組來儲存。同時,當解析最終編碼的時候,要刪除開始位左邊的位bit),從而獲得真正的變長編碼。

儘管許多人沒有意識到,事實上“時間間隔”是定義莫斯代碼的主要因素,所以理解這一點是產生莫斯代碼的關鍵。所以,我們要做的第一件事,就是定義莫 斯代碼的內部碼即“嘀”和“嗒”)的時間間隔。為了方便起見,我們定義一個“嘀”的聲音長度為一個時間單位dt,“嘀”和“嗒”之間的間隔也是一個時間 單位dt;定義一個“嗒”的長度為3個dt,字元letters)之間的間隔也是3個dt;定義單詞words)之間的間隔是7個dt。所以,總結起 來,我們的時間間隔表就像下面這樣:

項目

時間長度

dt

“嘀”/“嗒”之間的間隔

dt

“嗒”

3*dt

字元之間的間隔

3*dt

單詞之間的間隔

7*dt

在莫斯代碼中,編碼聲音的“播放速度”通常用 單詞數/分鐘(WPM) 來表示。由於英文單詞有不同的長度,而且字元也有不同數量的“嘀”和“嗒”,所以,從WPM轉化成音頻)數字採樣並不是看上去那樣簡單。在一份被國際組 織採用的方案中,採用5個字元作為單詞的平均長度,同時,一個數字或標點符號被當做2個字元。這樣,平均一個單詞就是50個時間單位dt。這樣,如果你指 定了WPM,那麼我們總的播放時間就是 50 * WPM的時間單位/分鐘,每個“嘀”即一個時間單位dt)的長度等於1.2/WPM秒。這樣,給出一個“嘀”的時間長度,其他元素的時間長度很容易就能 夠計算出來。

你可能已經注意到,在上面顯示的網頁中,對於低於15WPM的選項,我們使用了“Farnsworth spacing”。那麼這個“Farnsworth spacing”又是個什麼鬼?

當報務員學慣用耳朵來解碼莫斯代碼的時候,他就會意識到,當播放速度變化的時候,字元出現的節奏也會跟著變化。當播放速度低於10WPM的時候,他 能夠從容的識別“嘀”和“嗒”,並且知道發送的哪個字元。但是當播放速度超過10WPM的時候,報務員的識別就會出錯,他識別出來的字元會多於實際的 “嘀”和“嗒”。當一個學習的時候習慣低速莫斯代碼的人,在處理高速播放代碼的時候,就會出現問題。因為節奏變了,他潛意識的識別就會出錯。

為瞭解決這個問題,“Farnsworth spacing”就被發明出來了。本質上來講,字母和符號的播放速度依然採取高於15WPM的速度,同時,通過在字元之間插入更多的空格,來使整體的播放 速度降低。這樣,報務員就能夠以一個合理的速度和節奏來識別每個字元,一旦所有的字元都學習完畢,就可以增加速度,而接收員只需要加快識別字元的速度就可 以了。本質上來說,“Farnsworth spacing”這個技巧解決了節奏變化這個問題,使接收員能夠快速學習。

所以,在整個系統中,對於更低的播放速度,都統一成15WPM。相對應的,一個“嘀”的長度是0.08秒,但是字元之間和單詞之間的間隔就不再是3個dit或者7個dit,而是進行的調整以適應整體速度。

產生聲音

在PHP代碼中,一個字元即前面數組的索引)代表一組由“嘀”、“嗒”和空白間隔組成的莫斯聲音。我們用數字採樣來組成音頻序列,並且將其寫入到檔案中,同時加上適當的頭資訊來將其定義成WAVE格式。

產生聲音的代碼其實相當簡單,你可以在項目中PHP檔案中找到它們。我發現定義一個“數字振蕩器”相當方便。每調用一次osc(),它就會返回一個 從正玄波產生的定時採樣。運用聲音採樣和聲頻規範,產生WAVE格式的音頻已經足夠了。在產生的正玄波中的-1到+1之間是被移動和調整過的,這樣聲音的 位元組資料可以用0到255來表示,同時128表示零振幅。

同時,在產生聲音方面我們還要考慮另外一個問題。一般來講,我們是通過正玄波的開關來產生莫斯代碼。但是你直接這樣來做的話,就會發現你產生的訊號會佔用非常大的頻寬。所以,通常無線電裝置會對其加以修正,以減少頻寬佔用。

在我們的項目中,也會做這樣的修正,只不過是用數位方式。既然我們已經知道了一個最小聲音樣本“嘀”的時間長度,那麼,可以證明,最小頻寬的聲幅 發生在長度等於“嘀”的正玄波半周期。事實上,我們使用低通濾波器low pass filter)來過濾音頻訊號也能達到同樣的效果。不過,既然我們已經知道所有的訊號字元,我們直接簡單的過濾一下每一個字元訊號就可以了。

產生“嘀”、“嗒”和空白訊號的PHP代碼就像下面這樣:

 
  1. while ($dt < $DitTime) {
  2. $x = Osc();
  3. if ($dt < (0.5*$DitTime)) {
  4. // Generate the rising part of a dit and dah up to half the dit-time
  5. $x = $x*sin((M_PI/2.0)*$dt/(0.5*$DitTime));
  6. $ditstr .= chr(floor(120*$x+128));
  7. $dahstr .= chr(floor(120*$x+128));
  8. }
  9. else if ($dt > (0.5*$DitTime)) {
  10. // For a dah, the second part of the dit-time is constant amplitude
  11. $dahstr .= chr(floor(120*$x+128));
  12. // For a dit, the second half decays with a sine shape
  13. $x = $x*sin((M_PI/2.0)*($DitTime-$dt)/(0.5*$DitTime));
  14. $ditstr .= chr(floor(120*$x+128));
  15. }
  16. else {
  17. $ditstr .= chr(floor(120*$x+128));
  18. $dahstr .= chr(floor(120*$x+128));
  19. }
  20. // a space has an amplitude of 0 shifted to 128
  21. $spcstr .= chr(128);
  22. $dt += $sampleDT;
  23. }
  24. // At this point the dit sound has been generated
  25. // For another dit-time unit the dah sound has a constant amplitude
  26. $dt = 0;
  27. while ($dt < $DitTime) {
  28. $x = Osc();
  29. $dahstr .= chr(floor(120*$x+128));
  30. $dt += $sampleDT;
  31. }
  32. // Finally during the 3rd dit-time, the dah sound must be completed
  33. // and decay during the final half dit-time
  34. $dt = 0;
  35. while ($dt < $DitTime) {
  36. $x = Osc();
  37. if ($dt > (0.5*$DitTime)) {
  38. $x = $x*sin((M_PI/2.0)*($DitTime-$dt)/(0.5*$DitTime));
  39. $dahstr .= chr(floor(120*$x+128));
  40. }
  41. else {
  42. $dahstr .= chr(floor(120*$x+128));
  43. }
  44. $dt += $sampleDT;
  45. }

WAVE格式的檔案

WAVE是一種通用的音頻格式。從最簡單的形式來看,WAVE檔案通過在頭部包含一個整數序列來表示指定採樣率的音頻振幅。關於WAVE檔案的詳細資料請查看這裡Audio File Format Specifications website。 對於產生莫斯代碼,我們並不需要用到WAVE格式的所有參數選項,僅僅需要一個8位的單聲道就可以了,所以,so easy。需要注意的是,多位元組資料需要採用低位優先little-endian)的位元組順序。WAVE檔案使用一種由叫做“塊chunks)”的記 錄組成的RIFF格式。

WAVE檔案由一個ASCII標識符RIFF開始,緊跟著一個4位元組的“塊”,然後是一個包含ASCII字元WAVE的頭資訊,最後是定義格式的資料和聲音資料。

在我們的程式中,第一個“塊”包含了一個格式說明符,它由ASCII字元fmt和一個4倍位元組的“塊”。在這裡,由於我使用的是普通脈衝編碼調製 plain vanilla PCM)格式,所以每個“塊”都是16位元組。然後,我們還需要這些資料:聲道數、聲音採樣/秒、平均位元組/秒、一個區塊block)對齊指標、位 bit)/聲音採樣。另外,由於我們不需要高品質立體聲,我們只採用單聲道,我們使用 11050採樣/秒標準的CD品質音訊採樣率是 44200 採樣/秒)的採樣率來產生聲音,並且用8位bit)儲存。

最後,真實的音頻資料儲存在接下來的“塊”中。其中包含ASCII字元data,一個4位元組的“塊”,最後是由位元組序列因為我們採用的是8位(bit)/採樣)組成的真實音頻資料。

在程式中,由8位音頻振幅序列組成的聲音儲存在變數$soundstr中。一旦音頻資料產生完畢,就可以計算出所有的“塊”大小,然後就可以把它們 合并在一起寫入磁碟檔案中。下面的代碼展示了如何產生頭資訊和音頻“塊”。需要注意的是,$riffstr表示RIFF頭,$fmtstr表示“塊”格 式,$soundstr表示音頻資料“塊”。

 
  1. $riffstr = 'RIFF'.$NSizeStr.'WAVE';
  2. $x = SAMPLERATE;
  3. $SampRateStr = '';
  4. for ($i=0; $i<4; $i++) {
  5. $SampRateStr .= chr($x % 256);
  6. $x = floor($x/256);
  7. }
  8. $fmtstr = 'fmt '.chr(16).chr(0).chr(0).chr(0).chr(1).chr(0).chr(1).chr(0)
  9. .$SampRateStr.$SampRateStr.chr(1).chr(0).chr(8).chr(0);
  10. $x = $n;
  11. $NSampStr = '';
  12. for ($i=0; $i<4; $i++) {
  13. $NSampStr .= chr($x % 256);
  14. $x = floor($x/256);
  15. }
  16. $soundstr = 'data'.$NSampStr.$soundstr;

總結和評論

我們的文本莫斯代碼產生器目前看起來還不錯。當然,我們還可以對它做很多的修改和完善,比如使用其他字元集、直接從檔案中讀取文本、產生壓縮音頻等等。因為我們這個項目的目的是使其能夠在網路上方便的使用,所以我們這個簡單的方案,已經達到我們的目的了。

當然,一如既往的,希望大家對這些簡單粗暴的代碼提出建議。這些年來雖然一直有人在教我,但我還是缺乏莫斯代碼相關背景知識,所以,如果出現任何的錯誤或遺漏都算是我的錯。

譯文連結:http://www.codeceo.com/article/php-morse-code-generation.html
英文原文:Morse Code Generation from Text

http://www.bkjia.com/PHPjc/1089381.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/1089381.htmlTechArticlePHP實現基於文本的莫斯電碼產生器 介紹 我最近遇到一個基於輸入文本產生摩斯代碼音頻檔案的需求。幾番搜尋無果之後,我決定自己編寫...

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.