步驟1:了解格式
磁性編碼條帶數(shù)據(jù)遵循通用標(biāo)準(zhǔn)。磁條由3條物理上分開(kāi)的“磁道”組成。磁道1最靠近卡的底部,磁道3最高。 Square的讀取器位于讀取軌道2的位置。軌道2是最常用的軌道,但是大多數(shù)信用卡也使用軌道1。軌道2包括卡號(hào)和有效期。音軌1包括那個(gè)加號(hào)。根據(jù)特定的卡,可能還會(huì)有其他數(shù)據(jù)。這些磁道的寬度規(guī)定為0.11英寸,因此要使用Square的讀取器讀取磁道1,我們只需要重新布置條紋,使磁道1與讀取頭對(duì)齊即可。
每個(gè)磁道中的數(shù)據(jù)均通過(guò)磁編碼域翻轉(zhuǎn)。長(zhǎng)話短說(shuō):一系列的域翻轉(zhuǎn)對(duì)波形進(jìn)行編碼,該波形被解釋為二進(jìn)制。此編碼中的二進(jìn)制0是任意頻率。 1是該頻率的兩倍。
數(shù)據(jù)以一組前導(dǎo)零開(kāi)始,以建立基本頻率。在可變數(shù)目的零之后,出現(xiàn)開(kāi)始標(biāo)記。對(duì)于音軌2,開(kāi)始標(biāo)記為“;”。每個(gè)字符被編碼為整數(shù),最低有效位在前。對(duì)于磁道2,每個(gè)字符包含4個(gè)數(shù)據(jù)位和1個(gè)奇偶校驗(yàn)位。為每個(gè)字符設(shè)置奇偶校驗(yàn)位,以使1的數(shù)量為奇數(shù)。如果為每個(gè)字符的整數(shù)值加上48(ASCII編碼為“ 0”),則將顯示ASCII字符。除了數(shù)字“ 0”到“ 9”之外,磁道2還可以編碼一些其他字符,包括“;”。 (開(kāi)始標(biāo)記),“ =“(字段分隔符)和“?” (末尾)。
步驟2:制作墊片以讀取音軌1
磁卡的磁道1比磁道2更靠近卡的邊緣.11英寸。由于Square讀卡器被設(shè)置為讀取磁道2,因此如果我們?cè)诖诺乐姓迟N一些東西,讀取器將卡提升.11英寸時(shí),讀取頭將與軌道1對(duì)齊,而不是與軌道2對(duì)齊。
您可以通過(guò)從另一張卡上剪切0.11英寸的條來(lái)創(chuàng)建墊片。我還發(fā)現(xiàn)廉價(jià)垃圾袋的纏結(jié)也差不多。
第3步:錄制一些音頻
就電話而言,Square閱讀器只是一個(gè)麥克風(fēng)。因此,要從卡中獲取數(shù)據(jù),我們需要記錄音頻。請(qǐng)參閱其他Android文檔(例如本教程:http://eurodev.blogspot.com/2009/09/raw-audio-manipulation-in-android.html)以獲取詳細(xì)說(shuō)明,或使用RhombusLib(請(qǐng)參閱最后的鏈接) )。以下是一些Java代碼,可以開(kāi)始在Android應(yīng)用中記錄音頻:
AudioRecord audioRecord =新的AudioRecord(MediaRecorder.AudioSource.MIC,
頻率,channelConfiguration,
audioEncoding,bufferSize);
audioRecord.startRecording();
錄音時(shí),我們需要不斷從錄音機(jī)中讀取數(shù)據(jù)并將其放入緩沖區(qū)中。
//創(chuàng)建一個(gè)DataOutputStream以寫入音頻數(shù)據(jù)
ByteArrayOutputStream os = new ByteArrayOutputStream ();
BufferedOutputStream bos =新的BufferedOutputStream(os);
DataOutputStream dos =新的DataOutputStream(bos);
short bufferVal;
short [] buffer = new short [bufferSize];
while(recording){
bufferReadResult = audioRecord.read(buffer,0,bufferSize);
for(int i = 0; i bufferVal = buffer [i];
dos.writeShort(buffer [i]);
}
}
dos.close();
byte [] audioBytes = os.toByteArray();
上面的代碼是從RhombusLib中提取并簡(jiǎn)化的。錄制后,您將擁有一個(gè)字節(jié)數(shù)組,代表麥克風(fēng)中的樣本,可以進(jìn)行分析。
步驟4:解碼音頻
因此,現(xiàn)在我們的設(shè)備上有很多音頻。我們?nèi)绾谓獯a它?我的代碼基于Android教程,該教程顯示了如何記錄數(shù)據(jù)然后進(jìn)行回放。就我而言,我確保將音頻保存為16位PCM編碼。我以44100hz采樣。在Android(以及其他地方,我想)上,16位PCM數(shù)據(jù)意味著每個(gè)樣本都是一個(gè)帶符號(hào)的16位值。因?yàn)槲覀冎魂P(guān)心頻率,所以我們只需要關(guān)心“零交叉”之間有多少時(shí)間。過(guò)零是指信號(hào)從正向變?yōu)樨?fù),反之亦然。 0位將由2個(gè)交叉點(diǎn)之間的間隔表示,而1將在大約相同的時(shí)間段內(nèi)有一個(gè)額外的交叉點(diǎn)。
每個(gè)磁道中的卡數(shù)據(jù)以一些(可變)數(shù)0開(kāi)始,以建立基本頻率。我所做的是聽(tīng)取高于某個(gè)“安靜”閾值的第一個(gè)樣本,然后計(jì)算零交叉之間的樣本數(shù)。該數(shù)字將成為0的基值。由于這些卡是手工刷卡的,因此從掃描開(kāi)始到結(jié)束,實(shí)際頻率將有所變化。因此,我做了一個(gè)簡(jiǎn)單的方法,確定自上次零交叉以來(lái)的樣本數(shù)量是否更接近基本頻率或兩倍于基本頻率(基本樣本數(shù)量的一半)。然后,它會(huì)相應(yīng)地調(diào)整預(yù)期的基本頻率。只要兩個(gè)邏輯位之間的變化很小,此方法就可以很好地工作。而且它們幾乎肯定會(huì)。
要檢測(cè)零交叉,我們需要查看每個(gè)樣本的符號(hào)并將其與前一個(gè)樣本的符號(hào)進(jìn)行比較。如果它們不同(一個(gè)正,一個(gè)負(fù)),則信號(hào)在這些樣本之間越過(guò)0。
基本算法是遍歷字節(jié)數(shù)組,提取樣本。計(jì)算零交叉之間的樣本數(shù),并將其與0或1的預(yù)期計(jì)數(shù)進(jìn)行比較。好的,經(jīng)過(guò)一番揮舞之后,我們現(xiàn)在有了一個(gè)二進(jìn)制數(shù)據(jù)序列,我們想回過(guò)頭來(lái)。轉(zhuǎn)換成ASCII。最常見(jiàn)的編碼(也是我編寫的唯一處理程序)將每個(gè)字符編碼為一定數(shù)量的位,再加上一個(gè)奇偶校驗(yàn)位。對(duì)于音軌2,字符為4位,奇偶校驗(yàn)為1,組成5位組。從最低有效位到最高讀取位,最后一位是奇偶校驗(yàn)位。將奇偶校驗(yàn)位設(shè)置為使組中的1的個(gè)數(shù)為奇數(shù)。在我的實(shí)現(xiàn)中,我只是忽略了奇偶校驗(yàn)位,但這將有助于確定讀取是否正確。在磁道1中,字符的6位加上奇偶校驗(yàn)。
磁道的字符集也有所不同,但是兩者都是ASCII子集,具有一些偏移量。對(duì)于僅編碼一些符號(hào)和數(shù)字的磁道2,字符集從48開(kāi)始,這是“ 0”的ASCII碼。因此,如果我們得到0,0,0,0,1作為我們的角色,則將其變成0,加48,得到48。類似地,1,0,0,0,0為1。1 + 48 = 49 = ASCII“ 1”。
對(duì)于軌道1,字符集以“”(空格)開(kāi)頭,即ASCII32。因此,我們?cè)诮獯a的數(shù)字值上加上32,得到ASCII字符。之后,我們有了數(shù)據(jù),因此剩下的一切都只是在掛接UI膠水。
責(zé)任編輯:wv
-
Android
+關(guān)注
關(guān)注
12文章
3941瀏覽量
127719 -
BSQUARE
+關(guān)注
關(guān)注
0文章
5瀏覽量
8759 -
磁條卡
+關(guān)注
關(guān)注
0文章
8瀏覽量
6884
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論