在声音中绘图
本文演示了如何在音频文件的频谱表示中绘制图形。
引言
这个想法是将图像绘制到声音中。特别是,将图像绘制到声音的频谱表示中。声音可以用多种方式表示。特别是,可以用振幅-时间表示 (波形) 和 频率-时间表示 (频谱) 来绘制。前者显示声音在时间上的振幅
X 轴是时间,而 Y 轴是声音的振幅。另一种视图将音频信号显示为不同频率的组成部分
这里,X 轴是时间,而 Y 轴是频率。特别是,较浅的颜色(白色)表示特定频率分量的较高值,而较深的颜色(黑色)表示较低分量。在这里,可以看到声音在时间和频率上的变化。
快速傅里叶变换
傅里叶变换是一种将信号(在本例中为音频信号)转换为其频率域表示的操作。因此,可以查看输入信号中存在哪些频率。FFT 是一种有效地计算傅里叶变换的算法。
逆运算(逆快速傅里叶变换)从频率域获取数据,并给出时间域中的值。我们可以使用此算法来绘制声音。只需将绘制视为输入,就像它是信号的频谱表示一样。然后,我们应用 IFFT 算法,并检索音频波形,用于创建输出波文件。
程序
黑板是音频信号的频率-时间表示。可以使用开始按钮左侧的条形的颜色对其进行绘制。单击条形,可以更改颜色。使用较深的颜色(如深灰色)可以获得最佳效果。单击“开始”按钮后,IFFT 算法开始计算数据,并生成输出音频文件。
随便画点什么
我们可以使用 Cooledit 等程序查看结果。
代码
该程序是用 C# 编写的。我们在这里使用两个基本库
- Wave File Library 由 Garrett Hoofman 编写。该库已被用于生成 Wav 输出文件。
- 一个实现 IFFT 算法的库。
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WaveLibrary;
namespace Img2Wav
{
class Core_Img2Wav
{
private const double MAX_DATA = +50;
private const double MIN_DATA = -50;
private const String NoInputBitmap = "No input bitmap";
public Bitmap InputBitmap { get; set; }
public WaveFile OutputWav { get; set; }
public void Start()
{
int NumSamples = InputBitmap.Width * InputBitmap.Height;
byte[] Samples = new byte[NumSamples];
OutputWav = new WaveFile(1, 16, 44000);
if (InputBitmap == null) throw new Exception(NoInputBitmap);
double[] data = new double[InputBitmap.Height];
int w = 0;
for (int i = 0; i < InputBitmap.Width; i++)
{
for (int j = 0; j < InputBitmap.Height; j++)
{
Color C = InputBitmap.GetPixel(i,j);
data[j] = (C.R + C.G + C.B ) / 3;
}
FFT_Img2Wav.inverse(data);
for (int x = 0; x < data.Length; x++)
{
Samples[w] = (byte)(MAX_DATA * data[x]);
w++;
}
}
OutputWav.SetData(Samples,NumSamples);
}
}
}