神笔马良——把图形「画」在音频里(译文 Draw Into Sound)

来源:互联网 发布:java string变量 编辑:程序博客网 时间:2024/04/29 22:13

作者:野比 (conmajia@gmail.com)

时间:May, 2012

封面图片为野比原创,请勿未经允许私自引用


这是意大利人 Angelo Gattuso(evol76)2008 年 12 月 22 日发表的文章。由本人翻译成中文。

点击阅读原文(英文)

源码 DEMO

点我下载


原作者 Angelo Gattuso (evol76)

国籍 意大利 

Angelo Gattuso(安吉罗·刚图索——译者按)2003 年 11 月毕业于都灵理工大学软件工程专业。

他目前从事软件工程师,开发和策划商业软件。在 ASP.NET 和三层架构软件方面都有涉足。

他喜欢音乐、读书还有烹饪——其实他更喜欢吃。

 

介绍

本文的点子是「把图形画到声音里去」,尤其是画到声音的频域之中。

声音可以用多种方式表示。通常,可以用「幅度 - 时间」图(波形)和「频率 - 时间」图(频谱)来表示。

下图显示了声音在时域中的幅度波形:

 

 

图中,X 轴为时间,Y 轴为声音幅度。第二类音频信号的显示方式是显示其不同的频率组成:

 

 

图中,X 轴为时间,Y 轴为频率。浅色(白)代表高该频率成分强度较高,深色(黑)表示强度较低。

可以从图中看到,声音是如何在频率和时间上变化的。

 

快速傅里叶变换

快速傅里叶变换是将信号(在这里,就是音频信号)变换到其频域的一种操作。

之后,可以看到输入信号的频率组成方式。快速傅里叶变换(FFT)是一种高效计算傅里叶变换的算法。

 

 

逆操作(IFFT,逆傅里叶变换)从频域获取数据,输出时域值。我们可以利用该算法将图形画到音频中。

我们将图形作为频域信号的输入,然后应用 IFFT 算法,就可以得到音频的波形用于生成输出的 wave 文件。

 

程序

 

 

图中的黑板是音频信号的「频率 - 时间」图。点击「开始(Start)」按钮左边的方框,

可以改变画笔颜色,然后可以用该种颜色在黑板上绘制图形。

使用较深的颜色(如深灰)可以获得较好的处理结果。

点击「开始(Start)」按钮,利用 IFFT 算法计算数据,并生成输出音频文件。

现在我们画点东西:

 

 

我们可以用 Cooledit 之类的程序来查看结果。

(下图显示的是一个 wav 文件的「频率 - 时间」图,而非我们通常见到的波形图——译者按)

 

 

代码

程序使用 C# 编写。这里我们用到了 2 个基础库:

·Garrett Hoofman 的 Wave File Library。该库用于产生 wav 输出文件

·任意 IFFT 算法库

[csharp] view plaincopyprint?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4. using System.Drawing;  
  5. using WaveLibrary;  
  6.   
  7. namespace Img2Wav  
  8. {  
  9.     class Core_Img2Wav  
  10.     {  
  11.           
  12.         private const double MAX_DATA = +50;  
  13.         private const double MIN_DATA = -50;  
  14.   
  15.         private const String NoInputBitmap = "No input bitmap";  
  16.   
  17.         public Bitmap InputBitmap { getset; }  
  18.         public WaveFile OutputWav { getset; }  
  19.   
  20.         public void Start()  
  21.         {  
  22.             int NumSamples = InputBitmap.Width * InputBitmap.Height;  
  23.             byte[] Samples = new byte[NumSamples];  
  24.             OutputWav = new WaveFile(1, 16, 44000);  
  25.             if (InputBitmap == nullthrow new Exception(NoInputBitmap);  
  26.             double[] data = new double[InputBitmap.Height];  
  27.   
  28.             int w = 0;  
  29.             for (int i = 0; i < InputBitmap.Width; i++)   
  30.             {  
  31.                 for (int j = 0; j < InputBitmap.Height; j++)  
  32.                 {  
  33.                     Color C = InputBitmap.GetPixel(i,j);  
  34.                     data[j] = (C.R + C.G + C.B ) / 3;  
  35.                 }  
  36.   
  37.                 FFT_Img2Wav.inverse(data);  
  38.                                   
  39.                 for (int x = 0; x < data.Length; x++)  
  40.                 {  
  41.                     Samples[w] = (byte)(MAX_DATA * data[x]);  
  42.                     w++;  
  43.                 }  
  44.             }  
  45.   
  46.             OutputWav.SetData(Samples,NumSamples);  
  47.         }  
  48.     }  
  49. }  

许可

本文及相关源代码和文件,适用 The Code Project Open Licen (CPOL)

 

关于版权

前段时间和老外Aisha Ikram聊天(之前翻译过他的《C#快速入门》等作品),AI说有个中国朋友看到有他的文章,但署名不是他。AI就把链接

发给我,我一看是我翻译的,但我的名字和原发站都没有。哈哈,就剩「人棍」,那哥们给去头去尾切的光溜溜的。

其实说真的,我也觉得在中国老外的那些 License 都是防君子的。但好歹也要装一下吧?

哈哈,开玩笑,个人行为,个人负责。

原创粉丝点击