program wavnorm;

{$mode objfpc}{$H+}
{$linklib c}

{
    Volume normalizer.
    For GNU/Linux 64 bit version.
    Version: 1.
    Written on FreePascal (https://freepascal.org/).
    Copyright (C) 2025  Artyomov Alexander
    Used https://chat.deepseek.com/
    http://self-made-free.ru/
    aralni@mail.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
}

uses
  Classes, SysUtils, wavfileunit, vatypesunit;

procedure NormalizeWAV(const InputFile, OutputFile: string);
var
  WAVFile: TWAVFile;
  Amplitudes: TMultiChannelAmplitudeArray;
  SampleRate: Cardinal;
  NumChannels: Word;
  i, j: Integer;
  MaxAmplitude: Double;
  ScaleFactor: Double;
  F: File;
  FileSizeBytes: Integer;
  NumSamples: Integer;
begin
  try
    // Проверка существования файла
    if not FileExists(InputFile) then
    begin
      WriteLn('Ошибка: Файл "', InputFile, '" не существует.');
      Exit;
    end;

    // Проверка размера файла
    Assign(F, InputFile);
    Reset(F, 1); // Открываем файл в бинарном режиме
    try
      FileSizeBytes := System.FileSize(F);
      if FileSizeBytes = 0 then
      begin
        WriteLn('Ошибка: Файл "', InputFile, '" пуст.');
        Exit;
      end;
    finally
      Close(F);
    end;

    // Загрузка WAV-файла
    WriteLn('Загрузка WAV-файла: ', InputFile);
    WAVFile := TWAVFile.Create(InputFile);
    try
      // Загружаем данные из файла
      WAVFile.LoadFromFile(InputFile);

      SampleRate := WAVFile.GetSampleRate;
      NumChannels := WAVFile.GetNumChannels;

      // Вывод информации о файле
      WriteLn('Частота дискретизации: ', SampleRate, ' Гц');
      WriteLn('Количество каналов: ', NumChannels);
      WriteLn('Размер чанка данных: ', WAVFile.GetDataChunkSize, ' байт');

      // Проверка наличия данных
      if WAVFile.GetDataChunkSize = 0 then
      begin
        WriteLn('Ошибка: Файл не содержит данных или имеет некорректную структуру.');
        Exit;
      end;

      // Инициализация массива Amplitudes
      NumSamples := WAVFile.GetDataChunkSize div (NumChannels * (WAVFile.GetBitsPerSample div 8));
      SetLength(Amplitudes, NumChannels);
      for j := 0 to High(Amplitudes) do
        SetLength(Amplitudes[j], NumSamples);

      // Чтение амплитуд
      WAVFile.ReadAmplitudes(Amplitudes);

      // Поиск максимальной амплитуды
      MaxAmplitude := 0;
      for j := 0 to High(Amplitudes) do
      begin
        for i := 0 to High(Amplitudes[j]) do
        begin
          if Abs(Amplitudes[j][i]) > MaxAmplitude then
            MaxAmplitude := Abs(Amplitudes[j][i]);
        end;
      end;

      // Вычисление масштабирующего коэффициента
      if MaxAmplitude > 0 then
        ScaleFactor := 1.0 / MaxAmplitude
      else
        ScaleFactor := 1.0;

      WriteLn('Максимальная амплитуда: ', MaxAmplitude:0:4);
      WriteLn('Масштабирующий коэффициент: ', ScaleFactor:0:4);

      // Нормализация амплитуд
      for j := 0 to High(Amplitudes) do
      begin
        for i := 0 to High(Amplitudes[j]) do
        begin
          Amplitudes[j][i] := Amplitudes[j][i] * ScaleFactor;
        end;
      end;

      // Сохранение нормализованного WAV-файла
      WriteLn('Сохранение нормализованного WAV-файла: ', OutputFile);
      WAVFile.SaveToFile(OutputFile, Amplitudes, SampleRate, NumChannels, WAVFile.GetBitsPerSample);
    finally
      WAVFile.Free;
    end;
  except
    on E: Exception do
    begin
      WriteLn('Ошибка: ', E.Message);
      Exit;
    end;
  end;
end;

begin
  if ParamCount < 2 then
  begin
    WriteLn('Использование: wavnorm <input.wav> <output.wav>');
    Exit;
  end;

  NormalizeWAV(ParamStr(1), ParamStr(2));
end.