有个六局电波的西铁城,由于地理位置偏僻收不到波
网上看到了这个 《 BPC 电波授时信号的“零成本”伪造》 用 Python+耳机发射授时信号
上网查了查 在苹果商店发现一个 app 售价 12 但是没有苹果手机
觉得要是把他的代码改到 js 里面就可以在浏览器里面运行对时就非常方便了
目前只完成了时间转 base4 部分 但是 js 音频发声转换部分没有思路 对音频和波形没有研究过
看了两个库 timbre.js 和 lame.js 不知是否可行
python 代码
# -*- coding: utf-8 -*-
"""
Created on Tue Jan 19 15:26:45 2016
@author: zhengbowang
"""
import pyaudio
import struct
import datetime
import math
def dropandfill(l,s):return '0'*(l - len(s[2:])) + s[2:]#用 0 补位
def time2code(date_time, dt = datetime.timedelta(0)):
#将时间转换成 BPC 编码。
date_time -= dt
date = [date_time.day, date_time.month, date_time.year]
timet = [date_time.hour,date_time.minute,date_time.weekday()+1]
date[2] = date[2]%100#year
timet[0] = timet[0]%12#am.pm
p1 = dropandfill(2,bin(date_time.second/20))#seconds
p2 = '00'#reserved
sec1 = (p1+p2)+''.join(map(dropandfill,[4,6,4],map(bin,timet)))
p31 = str(int(date_time.hour>=12))
p32 = str((sec1.count('1'))%2)
p3 = p31 + p32
sec2 = ''.join(map(dropandfill,[6,4,6],map(bin,date)))
p41 = str(int(date_time.year%1000>100))
p42 = str(((sec2.count('1'))%2))
p4 = p41 + p42
code2 = sec1 + p3 +sec2 + p4
bin2four = {'00':'1','01':'2','10':'3','11':'4'}#to base4
return '0'+''.join([bin2four[code2[2*i:2*i+2]] for i in range(len(code2)/2)])
dt = datetime.timedelta(hours = 1)#fake time shift
samp_rate = 68500
freq = 6850 * 2 #in Hertz
ttime =20 #in Sec
SAMPLE_LEN = samp_rate * ttime # 20 seconds of cosine
value = ampl = 32725
div = samp_rate/freq/2
data = 32725
# 打开声音输出流
p = pyaudio.PyAudio()
stream = p.open(format = 8,
channels = 1,
rate = samp_rate,
output = True)
while True:
date_time = datetime.datetime.now()+dt
print date_time
sec = (date_time.second+1)%20
code_str = time2code(date_time)
start = sec * samp_rate
for i in xrange((start), SAMPLE_LEN):
#if i % div == 0:value = -value#carrier generate
value = ampl * int(math.cos(math.pi / float(div) * float(i)))
pulse = (i - sec * samp_rate)/(samp_rate / 10)
packed_value = struct.pack('h', int(pulse >= int(code_str[sec]))*value)
stream.write(packed_value)
if i % samp_rate == 0 and i != start:
sec = sec + 1
转到一半的 js 代码
function time2code(date_time) {
var date = [date_time.getDate(), date_time.getMonth() + 1, date_time.getFullYear()];
var timet = [date_time.getHours(), date_time.getMinutes(), date_time.getUTCDay()];
date[2] = date[2] % 100; //year
timet[0] = timet[0] % 12; //am,pm
var p1 = dropandfill(2, parseInt(date_time.getSeconds() / 20).toString(2)); //seconds
var p2 = '00'; //reserved
var sec1 = (p1 + p2) + '' + join(map(dropandfill, [4, 6, 4], map(bin, timet)))
var p31 = Number(date_time.getHours() >= 12).toString();
var re = new RegExp("1", "g");
var p32 = str((sec1.match(re).length) % 2)
var p3 = p31 + p32;
var sec2 = '' + join(map(dropandfill, [6, 4, 6], map(bin, date)));
var p41 = str(Number(date_time.getFullYear() % 1000 > 100))
var p42 = str(((sec2.match(re).length) % 2))
var p4 = p41 + p42
var code2 = sec1 + p3 + sec2 + p4
var bin2four = { '00': '1', '01': '2', '10': '3', '11': '4' } //to base4
var ret = [];
ret.push('0')
for (var i = 0; i < code2.length / 2; i++) {
ret.push(bin2four[code2.substring(i * 2, i * 2 + 2)]);
}
return join(ret);
}
//用 0 补位
function dropandfill(size, num) {
var s = "000000000" + num;
return s.substr(s.length - size);
}
function map(a, b) {
if (arguments.length == 2) {
for (var i = 0; i < arguments[1].length; i++) {
arguments[1][i] = arguments[0](arguments[1][i]);
}
return arguments[1];
}
if (arguments.length == 3) {
for (var i = 0; i < arguments[1].length; i++) {
arguments[1][i] = arguments[0](arguments[1][i], arguments[2][i]);
}
return arguments[1];
}
}
function bin(e) {
return e.toString(2);
}
function join(e) {
var ret = "";
for (var i = 0; i < e.length; i++) {
ret += e[i];
}
return ret;
}
function str(e) {
return e.toString();
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.