Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/34: Рейтинг темы: голосов - 34, средняя оценка - 4.71
0 / 0 / 0
Регистрация: 16.04.2015
Сообщений: 5

Создание .wav файла из списка амплитуд

24.11.2018, 22:50. Показов 7049. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, возникли трудности с функцией создания .wav файла. Сам файл она создает, беда в том, что по времени она сжимает сигнал в 2 раза. При этом во время прослушивания он с двойной скоростью. Исходный файл: *скриншот*. Файл после создания из амплитуд и его открытия: *скриншот*. Из всех моих попыток - это самая близкая к оригиналу, но увы, с неприятным дефектом по времени. Буду рад подсказке.

Функция
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void CreateWavFile(QString FilePath, QVector<double> Amplitude, int VectorSize)
{
    uint16_t Data;
    wav_hdr wavHeader;
    wavHeader.RIFF[0] = 'R'; wavHeader.RIFF[1] = 'I'; wavHeader.RIFF[2] = 'F'; wavHeader.RIFF[3] = 'F';
    wavHeader.WAVE[0] = 'W'; wavHeader.WAVE[1] = 'A'; wavHeader.WAVE[2] = 'V'; wavHeader.WAVE[3] = 'E';
    wavHeader.fmt[0] = 'f';  wavHeader.fmt[1] = 'm';  wavHeader.fmt[2] = 't';  wavHeader.fmt[3] = ' ';
    wavHeader.Subchunk2ID[0] = 'd'; wavHeader.Subchunk2ID[1] = 'a'; wavHeader.Subchunk2ID[2] = 't'; wavHeader.Subchunk2ID[3] = 'a';
    wavHeader.Subchunk1Size = 16;
    wavHeader.AudioFormat = 1;
    wavHeader.NumOfChan = 1;
    wavHeader.SamplesPerSec = 48000;
    wavHeader.bytesPerSec = 96000;
    wavHeader.bitsPerSample = 16;
    wavHeader.blockAlign = 2;
    wavHeader.Subchunk2Size = wavHeader.NumOfChan*(static_cast<unsigned int>(VectorSize))*wavHeader.blockAlign;
    wavHeader.ChunkSize = 4 + (8 + wavHeader.Subchunk1Size) + (8 + wavHeader.Subchunk2Size);
    size_t headerSize = sizeof(wav_hdr);
 
    QByteArray ByteFilePath = FilePath.toLatin1();
    const char *filePath = ByteFilePath.data();
 
    FILE* wavFile = fopen(filePath, "w");
    fwrite(&wavHeader, 1, headerSize, wavFile);
    fseek(wavFile, long(headerSize), SEEK_SET);    
    for(int i = 0; i < VectorSize; i++)
    {
        Data = uint16_t(Amplitude[i]);
        fwrite(&Data, 1, wavHeader.Subchunk1Size, wavFile);
        long position = i*sizeof(uint16_t) + headerSize;
        fseek(wavFile, position, SEEK_SET);
    }
    fclose(wavFile);
}

Структура
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
typedef struct  WAV_HEADER
{
    /* RIFF Chunk Descriptor */
    uint8_t         RIFF[4];        // RIFF Header Magic header
    uint32_t        ChunkSize = 0;      // RIFF Chunk Size
    uint8_t         WAVE[4];        // WAVE Header
    /* "fmt" sub-chunk */
    uint8_t         fmt[4];         // FMT header
    uint32_t        Subchunk1Size = 0;  // Size of the fmt chunk
    uint16_t        AudioFormat = 0;    // Audio format 1=PCM,6=mulaw,7=alaw,     257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
    uint16_t        NumOfChan = 0;      // Number of channels 1=Mono 2=Sterio
    uint32_t        SamplesPerSec = 0;  // Sampling Frequency in Hz
    uint32_t        bytesPerSec = 0;    // bytes per second
    uint16_t        blockAlign = 0;     // 2=16-bit mono, 4=16-bit stereo
    uint16_t        bitsPerSample = 0;  // Number of bits per sample
    /* "data" sub-chunk */
    uint8_t         Subchunk2ID[4]; // "data"  string
    uint32_t        Subchunk2Size = 0;  // Sampled data length
} wav_hdr;
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
24.11.2018, 22:50
Ответы с готовыми решениями:

NAudio - воспроизвести мелодию по значениям амплитуд из wav-файла
Всем привет! Подскажите, можно ли с помощью библиотеки NAudio воспроизвести мелодию, если у меня есть массив со значениями амплитуд из...

Создание WAV-файла
Здравствуйте, уважаемые мастера программирования. Помогите, пожалуйста, завершить программу. Благодаря учителю Ur Quan и классному...

Создание Wav файла.
У меня есть массив short data. В нем содержится дата из wav файла 16 - битного. Надо создать wav - ку, которая в конечном результате...

8
2732 / 887 / 330
Регистрация: 10.02.2018
Сообщений: 2,095
25.11.2018, 13:11
Лучший ответ Сообщение было отмечено onspeed13 как решение

Решение

fopen(filePath, "w") - зло
В остальном файл более менее рабочий получается по вашей программе.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <cstdint>
#include <cmath>
#include <Windows.h>
 
typedef struct  WAV_HEADER
{
    /* RIFF Chunk Descriptor */
    uint8_t         RIFF[4];        // RIFF Header Magic header
    uint32_t        ChunkSize;      // RIFF Chunk Size
    uint8_t         WAVE[4];        // WAVE Header
    /* "fmt" sub-chunk */
    uint8_t         fmt[4];         // FMT header
    uint32_t        Subchunk1Size;  // Size of the fmt chunk
    uint16_t        AudioFormat;    // Audio format 1=PCM,6=mulaw,7=alaw,     257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
    uint16_t        NumOfChan;      // Number of channels 1=Mono 2=Sterio
    uint32_t        SamplesPerSec;  // Sampling Frequency in Hz
    uint32_t        bytesPerSec;    // bytes per second
    uint16_t        blockAlign;     // 2=16-bit mono, 4=16-bit stereo
    uint16_t        bitsPerSample;  // Number of bits per sample
    /* "data" sub-chunk */
    uint8_t         Subchunk2ID[4]; // "data"  string
    uint32_t        Subchunk2Size;  // Sampled data length
} wav_hdr;
 
void CreateWavFile(const char* filePath, const double* Amplitude, int VectorSize)
{
    int16_t Data;
    wav_hdr wavHeader;
    wavHeader.RIFF[0] = 'R'; wavHeader.RIFF[1] = 'I'; wavHeader.RIFF[2] = 'F'; wavHeader.RIFF[3] = 'F';
    wavHeader.WAVE[0] = 'W'; wavHeader.WAVE[1] = 'A'; wavHeader.WAVE[2] = 'V'; wavHeader.WAVE[3] = 'E';
    wavHeader.fmt[0] = 'f';  wavHeader.fmt[1] = 'm';  wavHeader.fmt[2] = 't';  wavHeader.fmt[3] = ' ';
    wavHeader.Subchunk2ID[0] = 'd'; wavHeader.Subchunk2ID[1] = 'a'; wavHeader.Subchunk2ID[2] = 't'; wavHeader.Subchunk2ID[3] = 'a';
    wavHeader.Subchunk1Size = 16;
    wavHeader.AudioFormat = 1;
    wavHeader.NumOfChan = 1;
    wavHeader.SamplesPerSec = 48000;
    wavHeader.bytesPerSec = 96000;
    wavHeader.bitsPerSample = 16;
    wavHeader.blockAlign = 2;
    wavHeader.Subchunk2Size = VectorSize * wavHeader.blockAlign;
    //wavHeader.NumOfChan*(static_cast<unsigned int>(VectorSize))*wavHeader.blockAlign;
    wavHeader.ChunkSize = sizeof(wav_hdr) - 8 + wavHeader.Subchunk2Size;
    // wavHeader.ChunkSize = 4 + (8 + wavHeader.Subchunk1Size) + (8 + wavHeader.Subchunk2Size);
    size_t headerSize = sizeof(wav_hdr);
 
    FILE* wavFile = fopen(filePath, "wb"); // <-----------  !!!!!!!!!!!!!!!!!!!!!!
    //FILE* wavFile = fopen(filePath, "w");
    fwrite(&wavHeader, 1, headerSize, wavFile);
    //fseek(wavFile, long(headerSize), SEEK_SET);    
    for(int i = 0; i < VectorSize; i++)
    {
        Data = int16_t(Amplitude[i]);
        fwrite(&Data, 2, 1, wavFile);
        //fwrite(&Data, 1, wavHeader.Subchunk1Size, wavFile);
        //long position = i*sizeof(uint16_t) + headerSize;
        //fseek(wavFile, position, SEEK_SET);
    }
    fclose(wavFile);
}
 
int main()
{
    double data[48000];
    for (int i=0; i<48000; i++)
        data[i] = 10000.0 * sin(2 * 3.14 * i / 48);
 
    CreateWavFile("test.wav", data, 48000);
 
    system("pause");
    return 0;
}
1
0 / 0 / 0
Регистрация: 16.04.2015
Сообщений: 5
25.11.2018, 16:25  [ТС]
Ygg, cпасибо вам за подсказку, про зло запомню

Сама проблема со сжиманием решилась изменением этих строк, вдруг кому еще поможет:

C++ (Qt)
1
2
3
4
5
6
7
int32_t Data;
wavHeader.Subchunk2Size = 2 * VectorSize * wavHeader.blockAlign;
for(int i = 0; i < VectorSize; i++)
{
     Data = int32_t(Amplitude[i]);
     fwrite(&Data, 4, 1, wavFile);
}
0
2732 / 887 / 330
Регистрация: 10.02.2018
Сообщений: 2,095
25.11.2018, 21:11
Цитата Сообщение от onspeed13 Посмотреть сообщение
Сама проблема со сжиманием решилась изменением этих строк
Если вы не меняли остальных параметров файла, то это ошибочное решение. После предыдущих исправлений ваш код создаёт ровно столько, сколько заказано. Возможно проблема "сжатия" связана с чтением или чем-то ещё, но не с записью. Двоечка в вашем решении и четыре байта на семпл немного намекают на необходимость создания стерео-файла.
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Моно файл (NumOfChan = 1):
  bps   - bitsPerSample / 8 = 16 / 8 = 2
  block - blockAlign = 2
+---------+---------+---------+---------+-------
| 1 семпл | 2 семпл | 3 семпл | 4 семпл | ...
+---------+---------+---------+---------+-------
|         |
|   bps   |
|<------->|
|         |
|  block  |
|<------->|
 
Стерео файл (NumOfChan = 2):
  bps   - bitsPerSample / 8 = 16 / 8 = 2
  block - blockAlign = 4
+-------------+-------------+-------------+-------------+------
| 1 семпл (L) | 1 семпл (R) | 2 семпл (L) | 2 семпл (R) | ...
+-------------+-------------+-------------+-------------+------
|             |             |
|     bps     |             |
|<----------->|             |
|                           |
|           block           |
|<------------------------->|
1
0 / 0 / 0
Регистрация: 16.04.2015
Сообщений: 5
15.12.2018, 01:27  [ТС]
Ygg, действительно проблема оказалась в считывании амплитуд. Функция выдает в 2 раза меньше амплитуд, чем длительность аудиофайла (умудрился же я упустить этот момент). В каком направлении может быть ошибка?

Функция
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
QVector<double> AmpFromWav(QString FilePath)
{
    wav_hdr wavHeader;
    size_t headerSize = sizeof(wav_hdr);
    QByteArray ByteFilePath = FilePath.toLatin1();
    const char *filePath = ByteFilePath.data();
    FILE* wavFile = fopen(filePath, "rb");    
    if(wavFile != nullptr)
    {
        fread(&wavHeader, 1, headerSize, wavFile);
        int massSize = wavHeader.Subchunk2Size / wavHeader.blockAlign;
        fseek(wavFile, long(headerSize), SEEK_SET);
        int * Data = static_cast<int*>(malloc(sizeof(int) * massSize));
        fread(Data, 2, massSize, wavFile);
        QVector<double> Amplitude(massSize);
        for (int i=0; i < massSize ; i++)
        {
             Amplitude[i] = Data[i];
        }
        fclose(wavFile);
        return Amplitude;
    }
 }
0
2732 / 887 / 330
Регистрация: 10.02.2018
Сообщений: 2,095
15.12.2018, 11:09
Цитата Сообщение от onspeed13 Посмотреть сообщение
В каком направлении может быть ошибка?
Я не знаю, чего вы пытаетесь добиться. Если вы хотите сделать чтение исключительно своего файла, то читать нужно так же, как и пишите. Если вы хотите сделать универсальное чтение любого WAV-файла, то вам нужно пересмотреть структуру файла и алгоритм чтения.
Из явных ошибок бросается в глаза строка 14:
C++
1
fread(Data, 2, massSize, wavFile);
тут выполняется чтение 2*massSize байт, каждый int занимает 4 байта, значит вы читаете в два раза меньше, чем выделили в памяти.

Если рассмотреть более общий алгоритм, то сперва нужно проанализировать характеристики записанного звука: частоту, битность и количество каналов. Дальнейшие шаги должны зависеть от этих параметров. Если звук 16ти битный, то наиболее быстро его обрабатывать в 16ти битных целых типах (int16_t). Если звук 32ух битный, то обрабатывать его быстрее в 32ух битных целых типах (int32_t). Такое ветвление по типам приводит к необходимости создавать различные варианты функций выполняющие схожие действия. Это неудобно, поэтому звук иногда пытаются унифицировать, привести к какому-то единому типу и затем уже использовать только его для дальнейшей обработки. Если звук приводят к целому типу определённой битности, то при иной битности исходного звука нужно выполнять не просто присвоение, а ещё делать сдвиг на разницу бит. Если звук приводят к типу с плавающей точкой, то его не просто присваиваю, а нормируют к 1, т.е. делят на максимум возможной амплитуды для исходной битности. В любом случае, вы должны определить для себя как именно вы планируете работать с битностью, что делаете с многоканальностью, что делаете с частотами. Только после этого можно говорить о том, насколько код соответствует задуманному.
1
0 / 0 / 0
Регистрация: 16.04.2015
Сообщений: 5
15.12.2018, 15:45  [ТС]
Ygg, звуковой файл в любом случае идет с характеристиками в 16 бит, частотой 48000 и одним каналом (скажем как заданное условие). Приведение к типу с плавающей точкой выполняется уже после. Увеличил размер считываемого, судя по полученному результату все хорошо.
0
2732 / 887 / 330
Регистрация: 10.02.2018
Сообщений: 2,095
15.12.2018, 20:33
Цитата Сообщение от onspeed13 Посмотреть сообщение
звуковой файл в любом случае идет с характеристиками в 16 бит, частотой 48000 и одним каналом (скажем как заданное условие).
В таком случае wavHeader.blockAlign должен быть равен двум. Массив должен быть не int, а short. И память выделенную хорошо бы почистить.
C++
1
2
3
4
5
6
7
8
9
10
11
        fread(&wavHeader, 1, headerSize, wavFile);
        int massSize = wavHeader.Subchunk2Size / wavHeader.blockAlign;
        fseek(wavFile, long(headerSize), SEEK_SET);
        //int * Data = static_cast<int*>(malloc(sizeof(int) * massSize));
        short * Data = static_cast<int*>(malloc(2 * massSize));
        fread(Data, 2, massSize, wavFile);
        QVector<double> Amplitude(massSize);
        for (int i=0; i < massSize ; i++)
        {
             Amplitude[i] = Data[i];
        }
1
0 / 0 / 0
Регистрация: 16.04.2015
Сообщений: 5
15.12.2018, 21:22  [ТС]
Ygg, получается суть была в другой переменной меньшего размера. Теперь действительно получились точные значения. Спасибо вам большое.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
15.12.2018, 21:22
Помогаю со студенческими работами здесь

Создание WAV файла
Скажите, как создать wav файл с заданной частотой и разрешением звука? Команда WRITEWAV требует 4 аргумента, четвертым из которых...

Создание wav файла с внутренней функцией
Товарищи помогите разобраться, пытаюсь сделать следующее, у меня имеется функция f(x) = sin(x) пытаюсь её вогнать в файл wav что бы...

Создание нового Wav - файла, используя заголовок другого
Помогите пожалуйста! Задали такую задачу: надо полностью считать все о любом WAV файле (заголовок, сами данные), а потом записать их в...

Создание списка, печать списка на экран, добавления элемента в начало списка, конец списка
Построить динамическую структуру типа список . Необходимо реализовать следующие процедуры: 1. создание списка. 2. печать списка на...

Создание списка чисел из файла
Привет! Есть файл с набором чисел, нужно из этого файла взять числа и преобразовать в список file =...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru