Russian English
   Basic.net
Среда, 23.09.2020, 04:37
Меню сайта
Категории раздела
Basic [44]
Помощь [0]
Облако тегов
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Форма входа
Главная » Статьи » Basic

Библиотека lame_enc.dll. Кодируем в mp3 на FreeBasic
Share |
Урок от electrik/Lesson by elecktrik


Все мы знаем очень удобный формат mp3. это формат звуковых файлов, с плотной степенью сжатия, при этом, с хорошим качеством звучания. он поддерживается почти всеми устройствами, начиная от компьютера, dvd плеера и заканчивая наладонными системами и мобильными телефонами. есть огромное количество программ для кодирования в mp3, например, кодек lame, управляемый командной строкой или графической оболочкой razorlame, программа cdex, которая использует lame_enc.dll. Вот именно о lame_enc.dll пойдет речь.
иногда бывает нужно кодировать звуковой поток налету, например, звуковые шпионы, запись с радио, создание аудиокниг из голосовых движков text to speech и т.д. при кодировании на лету, желательно, чтобы компьютер обладал достаточными ресурсами. если кодирование mp3, будет отставать от реального времени, запись радиостанции, может быть не совсем удобной. можно понизить уровень качества, будет быстрое кодирование, но тогда качество сжатого звука, будет сильно отличаться от оригинала.
мы же пока не будем кодировать на лету, просто я вам покажу как работать с енкодером. данное описание не вкоем случае не претендует на роль полного. в комментариях заголовочного файла, будут вкратце, пояснены лишь некоторые члены структур.
сама программа почти ни чего не умеет, она лишь кодирует wav файлы с частотой дискретизации 44100, 16 бит. даже не проверяется заголовок wav файла, первые 44 байта пропускаются. так что если вы захотите кодировать файл отличающийся от данных параметров, скорее всего будут проблемы со скоростью звучания. в командной строке нужно указать имя wav файла. программа создаст файл типа: sound.wav.mp3. то есть, к введенному в командной строке, добавляется расширение .mp3.
вы можете скачать полный пакет, заголовочный файл+пример+интерфейсная библиотека+сам енкодер lame_enc.dll+документация по интерфейсу енкодера на английском языке+тестовый wav файл:
http://eric50.narod.ru/freebasic/lame.zip

Заголовочный файл BladeMP3EncDLL.bi
Code
' Blade Type of DLL Interface for Lame encoder
'
' Copyright © 1999-2002 A.L. Faber
  ' Based on bladedll.h version 1.0 written by Jukka Poikolainen
'
' This library is free software; you can redistribute it and/or
' modify it under the terms of the GNU Lesser General Public
' License as published by the Free Software Foundation; either
' version 2 of the License, or (at your option) any later version.
'  
' This library 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
' Lesser General Public License for more details.
'  
' You should have received a copy of the GNU Lesser General Public
' License along with this library; if not, write to the
' Free Software Foundation, Inc., 59 Temple Place - Suite 330,
' Boston, MA 02111-1307, USA.
' *** adapted to FreeBasic by Electrik

#include "windows.bi"
#inclib "lame_enc"
#ifndef __BLADEDLL_BI__
#define __BLADEDLL_BI__
#pragma once

' форматы кодирования
#define BE_CONFIG_MP3 0
#define BE_CONFIG_LAME 256

' объявление структур
type as dword HBE_STREAM
type as HBE_STREAM ptr PHBE_STREAM
type as dword BE_ERR

' коды ошибок
#define BE_ERR_SUCCESSFUL &h00000000
#define BE_ERR_INVALID_FORMAT &h00000001
#define BE_ERR_INVALID_FORMAT_PARAMETERS &h00000002
#define BE_ERR_NO_MORE_HANDLES &h00000003
#define BE_ERR_INVALID_HANDLE &h00000004
#define BE_ERR_BUFFER_TOO_SMALL &h00000005

' прочие константы
#define BE_MAX_HOMEPAGE 128

' format specific variables
#define BE_MP3_MODE_STEREO 0 ' стерео режим
#define BE_MP3_MODE_JSTEREO 1 ' джоинт стерео
#define BE_MP3_MODE_DUALCHANNEL 2 ' двойной канал
#define BE_MP3_MODE_MONO 3 ' моно режим

#define MPEG1 1 ' версия мпег
#define MPEG2 0 ' версия мпег. низкие битрейты и частоты дискретизации

#define CURRENT_STRUCT_VERSION 1
#define CURRENT_STRUCT_SIZE sizeof(BE_CONFIG) ' - к настоящему времени 331 байта

enum VBRMETHOD
VBR_METHOD_NONE = -1 ' отключить переменный битрейт
VBR_METHOD_DEFAULT = 0
VBR_METHOD_OLD = 1
VBR_METHOD_NEW = 2
VBR_METHOD_MTRH = 3
VBR_METHOD_ABR = 4
end enum

enum LAME_QUALITY_PRESET
LQP_NOPRESET =-1 ' использовать без готовых предустановок

' готовые предустановки качества звука и скорости кодирования
LQP_NORMAL_QUALITY = 0 ' нормальное качество
LQP_LOW_QUALITY = 1 ' низкое качество
LQP_HIGH_QUALITY = 2 ' высокое качество
LQP_VOICE_QUALITY = 3 ' качество для голоса
LQP_R3MIX = 4
LQP_VERYHIGH_QUALITY = 5 ' очень высокое качество
LQP_STANDARD = 6 ' стандарт
LQP_FAST_STANDARD = 7 ' стандарт, быстрое кодирование
LQP_EXTREME = 8 ' предел
LQP_FAST_EXTREME = 9 ' предел, быстрое кодирование
LQP_INSANE = 10 ' скоростное кодирование
LQP_ABR = 11 ' average bytrate
LQP_CBR = 12 ' постоянный битрейт
LQP_MEDIUM = 13
LQP_FAST_MEDIUM = 14

' новые готовые предустановки
LQP_PHONE = 1000 ' как по телефону
LQP_SW = 2000
LQP_AM = 3000 ' как средневолновый приемник
LQP_FM = 4000 ' как фм радио
LQP_VOICE = 5000 ' для голоса
LQP_RADIO = 6000 ' радио
LQP_TAPE = 7000 ' как на магнитофоне
LQP_HIFI = 8000 ' хай фай
LQP_CD = 9000 ' качество как у компакт диска
LQP_STUDIO = 10000 ' студийное качество
end enum

  type MP3 field = 1 ' BE_CONFIG_MP3
as dword dwSampleRate ' допустимо 48000, 44100 и 32000 килогерц
  as byte byMode ' режимы каналов, BE_MP3_MODE_STEREO, BE_MP3_MODE_DUALCHANNEL, BE_MP3_MODE_MONO. см. выше
  as word wBitrate ' допустимо 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256 и 320 килобит
  as BOOL bPrivate ' флажки. часный
as BOOL bCRC ' контрольная сумма
  as BOOL bCopyright ' авторское право
  as BOOL bOriginal
end type

type LHV1 field = 1 ' LAME header version 1

  ' информация о структуре
  as dword dwStructVersion ' версия структуры
  as dword dwStructSize ' размер структуры

' базовые установки енкодера
  as dword dwSampleRate ' частота дискретизации для входного файла
  as dword dwReSampleRate ' частота- для ресемплирования, 0=выбирается енкодером
  as LONG nMode ' режимы каналов, BE_MP3_MODE_STEREO, BE_MP3_MODE_DUALCHANNEL, BE_MP3_MODE_MONO. см. выше
  as dword dwBitrate ' устанавливает постоянный битрейт, для переменного минимальный
  as dword dwMaxBitrate ' постоянный битрейт игнорируется, устанавливает максимальный переменный битрейт
  as LONG nPreset ' используйте одну из готовых предустановок LAME_QUALITY_PRESET enum
  as dword dwMpegVersion ' версия mpeg. используйте, MPEG-1 или MPEG-2
  as dword dwPsyModel ' FUTURE USE, SET TO 0
  as dword dwEmphasis ' FUTURE USE, SET TO 0

' установка флагов в поток
  as BOOL SbPrivate ' установить часный бит (TRUE/FALSE)
  as BOOL IbCRC ' вставить контрольную сумму (TRUE/FALSE)
  as BOOL SbCopyright ' установить бит авторское право (TRUE/FALSE)
  as BOOL bOriginal ' Set Original Bit (TRUE/FALSE)
   
  ' VBR STUFF
  as BOOL bWriteVBRHeader ' WRITE XING VBR HEADER (TRUE/FALSE)
  as BOOL bEnableVBR ' включить переменный битрейт (TRUE/FALSE)
  as INTEGER nVBRQuality ' качество при переменном битрейте 0..9
  as dword dwVbrAbr_bps ' Использовать ABR вместо nVBRQuality
  as VBRMETHOD nVbrMethod ' метот vbr
  as BOOL bNoRes ' Disable Bit resorvoir (TRUE/FALSE)

  ' MISC SETTINGS
  as BOOL bStrictIso ' Use strict ISO encoding rules (TRUE/FALSE)
  as WORD nQuality ' установка качества, HIGH BYTE should be NOT LOW byte, otherwhise quality=5

  ' FUTURE USE , SET TO 0, align structure to 331 bytes
  as BYTE btReserved(255-4*sizeof(dword) - sizeof( WORD )-1)
end type

type AAC field = 1 ' aac
  as dword dwSampleRate ' частота дискретизации
  as BYTE byMode ' режим каналов
  as WORD wBitrate ' битрейт
  as BYTE byEncodingMethod ' метод кодирования
end type

  union FORMAT field = 1 'format
as MP3 mp3
as LHV1 lhv1
as AAC aac
end union

type BE_CONFIG field = 1
  as dword dwConfig ' BE_CONFIG_XXXXX
' поддерживается BE_CONFIG

as FORMAT format
end type

   
  type as BE_CONFIG ptr PBE_CONFIG

type BE_VERSION

  ' BladeEnc DLL номер версии
  as BYTE byDLLMajorVersion
  as BYTE byDLLMinorVersion

  ' BladeEnc номер версии движка (engine)
  as BYTE byMajorVersion
  as BYTE byMinorVersion

  ' дата релиза DLL
  as BYTE byDay  
as BYTE byMonth
  as WORD wYear

  'BladeEnc домашняя страница
  as zstring * BE_MAX_HOMEPAGE + 1 zHomepage

  as BYTE byAlphaLevel
  as BYTE byBetaLevel
  as BYTE byMMXEnabled

  as BYTE btReserved(125-1)
end type

type as BE_VERSION ptr PBE_VERSION

extern "c"

' функция инициализации потока
declare function beInitStream alias "beInitStream" _
(byval pbeConfig as PBE_CONFIG, byval dwSamples as PDWORD, _
byval dwBufferSize as PDWORD, byval phbeStream as PHBE_STREAM) as BE_ERR

' функция кодирования частей данных
declare function beEncodeChunk alias "beEncodeChunk" _
(byval hbeStream as HBE_STREAM, byval nSamples as DWORD, _
byval pSamples as PSHORT, byval pOutput as PBYTE, _
byval pdwOutput as PDWORD )as BE_ERR

'added for floating point audio -- DSPguru, jd
declare function beEncodeChunkFloatS16NI alias "beEncodeChunkFloatS16NI" _
(byval hbeStream as HBE_STREAM, byval nSamples as DWORD, _
byval buffer_l as PFLOAT, byval buffer_r as PFLOAT, _
byval pOutput as PBYTE, byval pdwOutput as PDWORD) as BE_ERR

' функция деинициализации потока
declare function beDeinitStream alias "beDeinitStream" _
(byval hbeStream as HBE_STREAM, byval pOutput as PBYTE, _
byval pdwOutput as PDWORD) as BE_ERR

' функция закрытия потока
declare function beCloseStream alias "beCloseStream" _
(byval hbeStream as HBE_STREAM) as BE_ERR

' функция получения версии енкодера
declare function beVersion alias "beVersion" _
(byval pbeVersion as PBE_VERSION) as PCVOID

declare function beWriteVBRHeader alias "beWriteVBRHeader" _
(byval lpszFileName as LPCSTR) as BE_ERR
declare function beFlushNoGap alias "beFlushNoGap" _
(byval hbeStream as HBE_STREAM, byval pOutput as PBYTE, _
byval pdwOutput as PDWORD) as BE_ERR
declare function beWriteInfoTag alias "beWriteInfoTag" _
(byval hbeStream as HBE_STREAM, byval lpszFileName as LPCSTR) as BE_ERR
end extern
#endif

Пример программы. Примечание: в программе за место стандартных функций вывода на экран, используется функция printf. во FreeBasic, данные функции есть в заголовочных файлах crt. c standart library functions.

Файл lame.bas

Code
' пример работы с енкодером lame
' основано на коде " * Copyright (c) 2000 A.L. Faber"
' оптимизировал под FreeBasic electrik
#include "windows.bi"
  #include "file.bi"
#include "crt.bi"
#include "BladeMp3EncDll.bi"

#define argc __fb_argc__ ' сделаем запись по удобней
#define argv __fb_argv__
dim as BE_VERSION Version ' структура версии енкодера
  dim as BE_CONFIG beConfig ' структура параметров енкодера
  dim as zstring * 255 strFileIn ' имя входного wav файла
dim as zstring * 255 strFileOut ' имя выходного mp3 файла  
  dim as DWORD dwSamples ' длина raw pcm данных
dim as dword dwMP3Buffer ' длина скодированных mp3 данных
  dim as HBE_STREAM hbeStream ' хэндл потока
  dim as BE_ERR beErr ' код ошибки
  dim as PBYTE pMP3Buffer ' буфер для скодированных mp3 данных
  dim as PSHORT pWAVBuffer ' буфер для raw pcm данных из wav файла
dim as integer fileIn ' номер входного файла
dim as integer fileOut ' номер выходного файла
if argc <> 2 then ' если аргументов <> 2 считая нулевой
  printf(!"Usage: %s <filename.wav>\n",*argv[0])
printf(!"example: %s sound.wav\n",*argv[0])  
printf(!"Descr: Short demo to show how to use the lame_enc.dll library file\n")
  printf(!"Note : WAV file is assumed to to have the following parameters\n")
  printf(!" : 44100 Hz, stereo, 16 Bits per sample\n")
  end -1
end if

' запишем в строки для имен файлов полученное имя из командной строки
' к строке выходного файла добавим .mp3
strFileIn = *argv[1]
strFileOut = *argv[1] & ".mp3"

beVersion(@version) ' получим версию енкодера

' отобразим элементы версии енкодера из структуры BE_VERSION
  printf _
  (!"lame_enc.dll version %u.%02u (%u/%u/%u)\n" _
  !"lame_enc Engine %u.%02u\n" _
  !"lame_enc homepage at %s\n\n", _  
  Version.byDLLMajorVersion, Version.byDLLMinorVersion, _
  Version.byDay, Version.byMonth, Version.wYear, _
  Version.byMajorVersion, Version.byMinorVersion, _
  Version.zHomepage)

if not fileExists(strFileIn) then ' если входной .wav файл не существует
  printf("Error opening %s, file not exists", argv[1]) ' выдаем ошибку
end -1 ' и выходим из программы
end if

fileIn = FreeFile ' получим номер для входного файла
open strFileIn for binary as #fileIn ' откроем в бинарном режиме
fileOut = FreeFile ' получим номер для выходного файла
open strFileOut for binary as #fileOut ' откроем в бинарном режиме

' заполним члены структуры be_Config  
beConfig.dwConfig = BE_CONFIG_LAME
  beConfig.format.LHV1.dwStructVersion = 1
  beConfig.format.LHV1.dwStructSize = sizeof(BE_CONFIG)  
  beConfig.format.LHV1.dwSampleRate = 44100
  beConfig.format.LHV1.dwReSampleRate = 0
  beConfig.format.LHV1.nMode = BE_MP3_MODE_JSTEREO
  beConfig.format.LHV1.dwBitrate = 128
  beConfig.format.LHV1.nPreset = LQP_R3MIX
  beConfig.format.LHV1.dwMpegVersion = MPEG1
  beConfig.format.LHV1.dwPsyModel = 0
  beConfig.format.LHV1.dwEmphasis = 0
  beConfig.format.LHV1.bOriginal = TRUE
  beConfig.format.LHV1.bWriteVBRHeader = TRUE
beConfig.format.LHV1.bNoRes = TRUE

' инициализируем поток (енкодер)  
beErr = beInitStream(@beConfig, @dwSamples, @dwMP3Buffer, @hbeStream)
   
  if beErr <> BE_ERR_SUCCESSFUL then ' если не равно ошибке
  printf("Error opening encoding stream (%lu)", beErr)
  end -1
end if
   
  pMP3Buffer = new byte [dwMP3Buffer] ' выделим память под mp3 данные
  pWAVBuffer = new short[dwSamples] ' выделим память для wav данных

if pMP3Buffer = 0 then
printf("not enough memory for mp3Buffer")
end -1
end if

if pWAVBuffer = 0 then
  printf("not enough memory for wavBuffer")
  end -1
  end if

  dim as DWORD dwRead ' число прочитанных элементов
  dim as DWORD dwWrite ' число записываемых mp3 данных в файл
  dim as DWORD dwDone ' насколько выполнено
  dim as DWORD dwFileSize ' длина wav файла

dwFileSize = lof(fileIn) ' получим длину файла
seek #fileIn,45 ' пропустим 44 байта заголовка wav файла
dwRead = 1 ' просто поставим 1, чтоб цикл сработал
while dwRead <> 0 ' пока недостигли конец файла

get #fileIn,,*pWAVBuffer,dwSamples,dwRead ' читаем часть wav данных
if dwRead = 0 then continue while ' можно exit while

' начинаем кодирование по частям
' dwRead/sizeof(SHORT)- это чтоб передать функции не число прочитанных байт,
'а число элементов длиной типа SHORT. SHORT- это 2 байта
beErr = beEncodeChunk(hbeStream, dwRead/sizeof(SHORT), pWAVBuffer, pMP3Buffer, @dwWrite)

if beErr <> BE_ERR_SUCCESSFUL then
  beCloseStream(hbeStream) ' если ошибка, закрываем поток
  printf("beEncodeChunk() failed (%lu)", beErr)
end -1
end if

' пишем mp3 данные в файл
if put( #fileOut,,*pMP3Buffer,dwWrite) <> 0 then
  printf("Output file write error")
end -1
end if
   
dwDone += dwRead

' выведем результат выполнения в процентах
  printf(!"Done: %0.2f%% \r", 100 * cast(SINGLE,dwDone)/cast(SINGLE,dwFileSize))
wend
' деинициализируем поток
  beErr = beDeinitStream(hbeStream, pMP3Buffer, @dwWrite)

  if beErr <> BE_ERR_SUCCESSFUL then
  beCloseStream(hbeStream) ' если ошибка, закрываем поток
  printf("beExitStream failed (%lu)", beErr)
  end -1
  end if

' может я не правильно перевел фразу.
  ' после вызова DeInit возвращаются любые байты?
  ' Если так, запишите их на диск
   
  ' // Are there any bytes returned from the DeInit call?
  ' // If so, write them to disk
  if dwWrite then
  if put( #fileOut,,*pMP3Buffer,dwWrite) <> 0 then
  'printf("Output file write error")
  end -1
end if
end if

  beCloseStream( hbeStream ) ' закроем поток

' очистим память от буферов
delete[] pWAVBuffer
delete[] pMP3Buffer
   
close ' закроем все открытые файлы

  'beWriteInfoTag( hbeStream, strFileOut ) ' пишет какой-то тег
   
  end 0 ' вернем операционке 0
Категория: Basic | Добавил: Admin (06.12.2010)
Просмотров: 5189 | Рейтинг: 3.5/2
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск
Наш опрос
Какую версию Basic вы предпочитаете?
Всего ответов: 2028

© Basic.ucoz.net, 2020