找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 5396|回复: 4

【VB】频谱图转WAV

[复制链接]
发表于 2014-7-29 21:34:56 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
原理就是一行一行地扫描位图,每一行作为一个频率的电平图,把像素点的亮度(红绿蓝平均值)作为电平,通过Sin函数制造波形,然后写入WAV文件。
代码很简单。另外我没有写行之间的插值的代码,所以位图的纵向长度直接决定了WAV波形频率线的数量。
用法:把图像文件直接拖进底部白色框。然后点“合成”。合成完了以后,你会在图片文件所在文件夹看到这个WAV文件。
这东西是表达恶意的强力工具之一{:soso_e144:}
20140729230911.png
经过转换得到的WAV用Gold Wave看到的频谱图是这个样子的:
WORI.PNG
拿耳机听到的就是一阵怪声,但是它的频谱图却包含了文字信息。这东西可以拿来做加密。就是加密后的数据特别大。。
范例: F2W.7z (154.66 KB, 下载次数: 52)
BIN: 频谱图转WAV.exe (36 KB, 下载次数: 6, 售价: 1 个宅币)
SRC: 频谱图转WAV.7z (12.03 KB, 下载次数: 1, 售价: 10 个宅币)
按照惯例给出源码。这个程序只有一个窗体文件。
  1. VERSION 5.00
  2. Begin VB.Form 主窗口
  3.    Caption         =   "频谱图转WAV"
  4.    ClientHeight    =   8085
  5.    ClientLeft      =   6435
  6.    ClientTop       =   3975
  7.    ClientWidth     =   9585
  8.    LinkTopic       =   "Form1"
  9.    ScaleHeight     =   539
  10.    ScaleMode       =   3  'Pixel
  11.    ScaleWidth      =   639
  12.    StartUpPosition =   3  '窗口缺省
  13.    Begin VB.PictureBox picProgress
  14.       Align           =   1  'Align Top
  15.       Height          =   255
  16.       Left            =   0
  17.       ScaleHeight     =   13
  18.       ScaleMode       =   3  'Pixel
  19.       ScaleWidth      =   635
  20.       TabIndex        =   12
  21.       Top             =   1455
  22.       Visible         =   0   'False
  23.       Width           =   9585
  24.       Begin VB.CommandButton cmdProgress
  25.          Enabled         =   0   'False
  26.          Height          =   195
  27.          Left            =   0
  28.          Style           =   1  'Graphical
  29.          TabIndex        =   13
  30.          Top             =   0
  31.          Width           =   90
  32.       End
  33.    End
  34.    Begin VB.PictureBox picTopPanel
  35.       Align           =   1  'Align Top
  36.       BorderStyle     =   0  'None
  37.       Height          =   1455
  38.       Left            =   0
  39.       ScaleHeight     =   1455
  40.       ScaleWidth      =   9585
  41.       TabIndex        =   1
  42.       Top             =   0
  43.       Width           =   9585
  44.       Begin VB.Frame frmAlgorithm
  45.          Caption         =   "算法"
  46.          Height          =   1335
  47.          Left            =   3960
  48.          TabIndex        =   15
  49.          Top             =   0
  50.          Width           =   1335
  51.          Begin VB.TextBox txtInterval
  52.             Height          =   270
  53.             Left            =   120
  54.             TabIndex        =   19
  55.             Text            =   "100"
  56.             Top             =   960
  57.             Width           =   855
  58.          End
  59.          Begin VB.OptionButton OpPerFreq
  60.             Caption         =   "逐频判断"
  61.             Height          =   180
  62.             Left            =   120
  63.             TabIndex        =   17
  64.             Top             =   480
  65.             Width           =   1095
  66.          End
  67.          Begin VB.OptionButton OpPerLine
  68.             Caption         =   "逐行判断"
  69.             Height          =   180
  70.             Left            =   120
  71.             TabIndex        =   16
  72.             Top             =   240
  73.             Value           =   -1  'True
  74.             Width           =   1095
  75.          End
  76.          Begin VB.Label lbllerpItv
  77.             AutoSize        =   -1  'True
  78.             Caption         =   "判断间隔:"
  79.             Height          =   180
  80.             Left            =   120
  81.             TabIndex        =   18
  82.             Top             =   720
  83.             Width           =   900
  84.          End
  85.       End
  86.       Begin VB.CommandButton cmdStop
  87.          Caption         =   "停止"
  88.          Enabled         =   0   'False
  89.          Height          =   375
  90.          Left            =   3000
  91.          TabIndex        =   14
  92.          Top             =   960
  93.          Width           =   855
  94.       End
  95.       Begin VB.Frame frmAnalyse
  96.          Caption         =   "分析"
  97.          Height          =   855
  98.          Left            =   2160
  99.          TabIndex        =   9
  100.          Top             =   0
  101.          Width           =   1695
  102.          Begin VB.OptionButton OpDarkness
  103.             Caption         =   "黑度决定电平"
  104.             Height          =   255
  105.             Left            =   120
  106.             TabIndex        =   11
  107.             Top             =   480
  108.             Width           =   1455
  109.          End
  110.          Begin VB.OptionButton OpBightness
  111.             Caption         =   "亮度决定电平"
  112.             Height          =   255
  113.             Left            =   120
  114.             TabIndex        =   10
  115.             Top             =   240
  116.             Value           =   -1  'True
  117.             Width           =   1455
  118.          End
  119.       End
  120.       Begin VB.CommandButton cmdMakeIt
  121.          Caption         =   "合成"
  122.          Enabled         =   0   'False
  123.          Height          =   375
  124.          Left            =   2160
  125.          TabIndex        =   8
  126.          Top             =   960
  127.          Width           =   855
  128.       End
  129.       Begin VB.TextBox txtMaxFreq
  130.          Height          =   270
  131.          Left            =   1200
  132.          TabIndex        =   7
  133.          Text            =   "22050"
  134.          Top             =   840
  135.          Width           =   855
  136.       End
  137.       Begin VB.TextBox txtMinFreq
  138.          Height          =   270
  139.          Left            =   1200
  140.          TabIndex        =   5
  141.          Text            =   "0"
  142.          Top             =   480
  143.          Width           =   855
  144.       End
  145.       Begin VB.TextBox txtPixelsPerSec
  146.          Height          =   270
  147.          Left            =   1200
  148.          TabIndex        =   3
  149.          Text            =   "40"
  150.          Top             =   120
  151.          Width           =   855
  152.       End
  153.       Begin VB.Label lblMaxFreq
  154.          AutoSize        =   -1  'True
  155.          Caption         =   "最大频率:"
  156.          Height          =   180
  157.          Left            =   120
  158.          TabIndex        =   6
  159.          Top             =   840
  160.          Width           =   900
  161.       End
  162.       Begin VB.Label lblMinFreq
  163.          AutoSize        =   -1  'True
  164.          Caption         =   "最小频率:"
  165.          Height          =   180
  166.          Left            =   120
  167.          TabIndex        =   4
  168.          Top             =   480
  169.          Width           =   900
  170.       End
  171.       Begin VB.Label lblPixelsPerSec
  172.          AutoSize        =   -1  'True
  173.          Caption         =   "每秒像素数:"
  174.          Height          =   180
  175.          Left            =   120
  176.          TabIndex        =   2
  177.          Top             =   120
  178.          Width           =   1080
  179.       End
  180.    End
  181.    Begin VB.PictureBox picSrc
  182.       Align           =   1  'Align Top
  183.       BackColor       =   &H80000005&
  184.       Height          =   5655
  185.       Left            =   0
  186.       OLEDropMode     =   1  'Manual
  187.       ScaleHeight     =   373
  188.       ScaleMode       =   3  'Pixel
  189.       ScaleWidth      =   635
  190.       TabIndex        =   0
  191.       Top             =   1710
  192.       Width           =   9585
  193.    End
  194. End
  195. Attribute VB_Name = "主窗口"
  196. Attribute VB_GlobalNameSpace = False
  197. Attribute VB_Creatable = False
  198. Attribute VB_PredeclaredId = True
  199. Attribute VB_Exposed = False
  200. Option Explicit

  201. Private Type WAVHeader 'WAV文件头,用来写WAV文件。
  202.     dwRIFF As Long
  203.     dwRIFFVal As Long
  204.     dwWAVE As Long
  205.     dwfmt As Long
  206.     dwfmtSize As Long
  207.     wPCM As Integer
  208.     wChannels As Integer
  209.     dwSampleRate As Long
  210.     dwByteRate As Long
  211.     wBytesPerSample As Integer
  212.     wBits As Integer
  213.     dwdata As Long
  214.     dwdataLen As Long
  215. End Type

  216. Private Type BITMAPINFO 'BMP信息头,给GetDIBits用的
  217.     biSize As Long
  218.     biWidth As Long
  219.     biHeight As Long
  220.     biPlanes As Integer
  221.     biBitCount As Integer
  222.     biCompression As Long
  223.     biSizeImage As Long
  224.     biXPelsPerMeter As Long
  225.     biYPelsPerMeter As Long
  226.     biClrUsed As Long
  227.     biClrImportant As Long
  228. End Type
  229. Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long

  230. Dim PicWidth As Long '图片尺寸
  231. Dim PicHeight As Long
  232. Dim ProgWidth As Single '进度条宽度

  233. Dim OutWAV As String '输出WAV文件的文件名
  234. Dim StopProc As Boolean

  235. Private Const PI As Double = 3.14159265358979
  236. Private Const SampleRate As Long = 44100

  237. '合成WAV文件
  238. Private Sub cmdMakeIt_Click()
  239. On Error GoTo ErrHandler
  240. SetAllEnabled False '防止重复操作
  241. picTopPanel.Enabled = True
  242. cmdStop.Enabled = True
  243. SetProgress 0
  244. picProgress.Visible = True
  245. StopProc = False

  246. Dim MinFreq As Double, MaxFreq As Double, FreqArea As Double, FreqInterval As Long, PixelsPerSec As Double
  247. If (IsNumeric(txtPixelsPerSec.Text) And _
  248.     IsNumeric(txtMinFreq.Text) And _
  249.     IsNumeric(txtMaxFreq.Text) And _
  250.     IsNumeric(txtInterval.Text)) = False Then
  251.     MsgBox "输入有误"
  252.     txtPixelsPerSec.Text = "40" '载入默认值然后退出
  253.     txtMinFreq.Text = "0"
  254.     txtMaxFreq.Text = "22050"
  255.     txtInterval.Text = "50"
  256.     GoTo ErrHandler
  257. End If

  258. PixelsPerSec = CDbl(txtPixelsPerSec.Text) '每秒像素数
  259. MinFreq = CDbl(txtMinFreq.Text) '最小频率
  260. MaxFreq = CDbl(txtMaxFreq.Text) '最大频率
  261. FreqInterval = CLng(txtInterval.Text)

  262. FreqArea = MaxFreq - MinFreq

  263. Dim TotalSamples As Long '样本总数
  264. TotalSamples = CDbl(PicWidth) * SampleRate / PixelsPerSec

  265. Dim Pitch As Long '图像每行字节数
  266. Dim Bits() As Byte '一行的图像数据
  267. Pitch = ((PicWidth * 3 - 1) \ 4 + 1) * 4

  268. Dim BI As BITMAPINFO 'BMP信息头
  269. With BI
  270.     .biSize = 40
  271.     .biWidth = PicWidth
  272.     .biHeight = PicHeight
  273.     .biPlanes = 1
  274.     .biBitCount = 24 '真彩色
  275.     .biSizeImage = Pitch * PicHeight
  276. End With

  277. Dim Values() As Double, MaxValue As Double, Value As Double
  278. Dim PValue As Double, NValue As Double '这一行的这个点的像素值,这一行的下个点的像素值
  279. ReDim Values(TotalSamples - 1) '计算出来的波形值

  280. Dim Darkness As Boolean '是否以“是否够黑”来做值大小判断标准
  281. Darkness = OpDarkness.Value

  282. Dim X&, XClr&, MaxX&
  283. Dim Y&, MaxY&, Progress As Double
  284. Dim S&, SB&, SE&, SD&, SI&
  285. Dim Freq&

  286. If OpPerFreq.Value Then
  287.     MaxX = PicWidth - 1
  288.     MaxY = PicHeight - 1
  289.     ReDim Bits(Pitch - 1)
  290.     For Freq = MinFreq To MaxFreq Step FreqInterval
  291.         Y = (Freq - MinFreq) * MaxY / FreqArea
  292.         Progress = CDbl(Y) / MaxY '取得进度
  293.         SetProgress CDbl(Freq - MinFreq) / FreqArea
  294.         
  295.         GetDIBits picSrc.hDC, picSrc.Picture.Handle, Y + 0, 1, Bits(0), BI, 0 '取得一行位图
  296.    
  297.         XClr = 0 '位图指针
  298.         For X = 0 To MaxX - 1 '处理每个像素
  299.             PValue = (CDbl(Bits(XClr + 0)) + Bits(XClr + 1) + Bits(XClr + 2)) / 765 '这个点的值
  300.             NValue = (CDbl(Bits(XClr + 3)) + Bits(XClr + 4) + Bits(XClr + 5)) / 765 '下个点的值
  301.             SB = X * TotalSamples / MaxX '这个点的样本索引(B=Begin)
  302.             SE = (X + 1) * TotalSamples / MaxX '下个点的样本索引(E=End)
  303.             SI = 0 '样本插值
  304.             SD = SE - SB '像素样本数
  305.             For S = SB To SE - 1
  306.                 Value = PValue + (NValue - PValue) * SI / SD '当前这行“音量”
  307.                 If Darkness Then Value = 1 - Value
  308.                 Values(S) = Values(S) + Sin(PI * 2 * Freq * S / SampleRate) * Value '添加到音轨
  309.                 If Abs(Values(S)) > MaxValue Then MaxValue = Abs(Values(S)) '取得音轨最大电平
  310.                 SI = SI + 1
  311.             Next
  312.             XClr = XClr + 3 '到下一个像素
  313.         Next
  314.         
  315.         DoEvents '反应一下以免假死被杀
  316.         If StopProc Then Exit For
  317.     Next
  318. Else
  319.     MaxX = PicWidth - 1
  320.     MaxY = PicHeight - 1
  321.     ReDim Bits(Pitch - 1)
  322.     For Y = 0 To MaxY - 1 '一行一行遍历位图
  323.         Progress = CDbl(Y) / MaxY '取得进度
  324.         SetProgress Progress
  325.         
  326.         Freq = MinFreq + (MaxFreq - MinFreq) * Progress  '当前频率
  327.         
  328.         GetDIBits picSrc.hDC, picSrc.Picture.Handle, Y, 1, Bits(0), BI, 0  '取得一行位图
  329.    
  330.         XClr = 0 '位图指针
  331.         For X = 0 To MaxX - 1 '处理每个像素
  332.             PValue = (CDbl(Bits(XClr + 0)) + Bits(XClr + 1) + Bits(XClr + 2)) / 765 '这个点的值
  333.             NValue = (CDbl(Bits(XClr + 3)) + Bits(XClr + 4) + Bits(XClr + 5)) / 765 '下个点的值
  334.             SB = X * TotalSamples / MaxX '这个点的样本索引(B=Begin)
  335.             SE = (X + 1) * TotalSamples / MaxX '下个点的样本索引(E=End)
  336.             SI = 0 '样本插值
  337.             SD = SE - SB '像素样本数
  338.             For S = SB To SE - 1
  339.                 Value = PValue + (NValue - PValue) * SI / SD '当前这行“音量”
  340.                 If Darkness Then Value = 1 - Value
  341.                 Values(S) = Values(S) + Sin(PI * 2 * Freq * S / SampleRate) * Value '添加到音轨
  342.                 If Abs(Values(S)) > MaxValue Then MaxValue = Abs(Values(S)) '取得音轨最大电平
  343.                 SI = SI + 1
  344.             Next
  345.             XClr = XClr + 3 '到下一个像素
  346.         Next
  347.         
  348.         DoEvents '反应一下以免假死被杀
  349.         If StopProc Then Exit For
  350.     Next
  351. End If

  352. If MaxValue = 0 And StopProc = False Then
  353.     MsgBox "这张图没有声音。"
  354.     GoTo ErrHandler
  355. End If

  356. Dim I&, Values16() As Integer
  357. ReDim Values16(UBound(Values)) 'WAV的16位样本

  358. For I = 0 To TotalSamples - 1 '转换为16位整数样本
  359.     Values(I) = Values(I) / MaxValue
  360.     Values16(I) = Values(I) * 32767
  361. Next

  362. Dim WAVH As WAVHeader 'WAV文件头
  363. With WAVH
  364.     .dwRIFF = &H46464952
  365.     .dwRIFFVal = 36 + (UBound(Values16) + 1) * 2
  366.     .dwWAVE = &H45564157
  367.     .dwfmt = &H20746D66
  368.     .dwfmtSize = 16
  369.     .wPCM = 1
  370.     .wChannels = 1 '单声道
  371.     .dwSampleRate = SampleRate
  372.     .dwByteRate = SampleRate * 2 * .wChannels
  373.     .wBytesPerSample = 2 * .wChannels
  374.     .wBits = 16
  375.     .dwdata = &H61746164
  376.     .dwdataLen = 0 + (UBound(Values16) + 1) * 2
  377. End With

  378. SetProgress 1 '显示一个完整的进度条,否则进度条缺着一块受不了
  379. DoEvents

  380. If Len(Dir$(OutWAV)) Then Kill OutWAV '干掉已有文件
  381. Open OutWAV For Binary As #1 '保存WAV
  382. Put #1, , WAVH '写文件头
  383. Put #1, , Values16 '写样本
  384. Close #1

  385. ErrHandler:
  386. picProgress.Visible = False '一切结束,隐藏进度条
  387. SetAllEnabled True '恢复所有控件
  388. cmdStop.Enabled = False
  389. StopProc = False
  390. If Err Then MsgBox Err.Description, vbExclamation, "出错"
  391. End Sub

  392. Private Sub cmdStop_Click()
  393. StopProc = True
  394. End Sub

  395. Private Sub Form_Resize()
  396. On Error Resume Next
  397. picSrc.Height = ScaleHeight - picSrc.Top
  398. End Sub

  399. Private Sub Form_Unload(Cancel As Integer)
  400. StopProc = True
  401. End Sub

  402. '通过拖拽打开图片文件。
  403. Private Sub picSrc_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single)
  404. picSrc.Picture = LoadPicture(Data.Files(1))
  405. OutWAV = GetOutWAVName(Data.Files(1))
  406. PicWidth = ScaleX(picSrc.Picture.Width, vbHimetric, vbPixels)
  407. PicHeight = ScaleY(picSrc.Picture.Height, vbHimetric, vbPixels)
  408. cmdMakeIt.Enabled = True
  409. End Sub

  410. '取得输出的WAV文件的文件名
  411. Function GetOutWAVName(ByVal StrFile As String) As String
  412. Dim RightSlash As Long, RightDot As Long
  413. RightSlash = InStrRev(StrFile, "")
  414. RightDot = InStrRev(StrFile, ".")
  415. If RightSlash > RightDot Then
  416.     GetOutWAVName = StrFile & ".wav"
  417. ElseIf RightDot > RightSlash Then
  418.     GetOutWAVName = Left$(StrFile, RightDot) & "wav"
  419. Else
  420.     GetOutWAVName = "C:\foo.wav"
  421. End If
  422. End Function

  423. '设置进度条位置,Prog的区间是[0,1]
  424. Sub SetProgress(ByVal Prog As Single)
  425. cmdProgress.Width = Prog * picProgress.ScaleWidth
  426. End Sub

  427. '设置所有控件是否灰色
  428. Sub SetAllEnabled(ByVal Val As Boolean)
  429. Dim Ctrl As Control
  430. For Each Ctrl In Controls
  431.     Ctrl.Enabled = Val
  432. Next
  433. End Sub
复制代码

本帖被以下淘专辑推荐:

回复

使用道具 举报

发表于 2014-7-30 11:09:55 | 显示全部楼层
这是威逼?
回复

使用道具 举报

 楼主| 发表于 2014-7-30 11:34:02 | 显示全部楼层

没错。
回复 赞! 靠!

使用道具 举报

发表于 2014-7-30 16:34:56 | 显示全部楼层
我囧= = 這有趣
回复 赞! 靠!

使用道具 举报

发表于 2014-12-21 07:11:50 | 显示全部楼层
vb学习中,非常有收获
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-23 16:07 , Processed in 0.042677 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表