AIMP Forum

AIMP for Windows => Дополнения / Addons => Разработка / Development => Topic started by: ugubok on June 23, 2017, 02:18:47

Title: Нужна помощь в портировании input плагина NotSo Fatso от Winamp (C++)
Post by: ugubok on June 23, 2017, 02:18:47
Недавно я начал портировать плагин-декодер NSF/NSFE файлов (NES Sound Format) под AIMP4. На данный момент AIMP4 умеет играть этот формат только посредством расширения ZXTune (https://www.aimp.ru/index.php?do=catalog&rec_id=627) над библиотекой BASS, которое является совершенно ненастраиваемым комбайном.

В отличии от ZXTune, NotSo Fatso нацелен лишь на NSF и имеет почти все возможные настройки для его воспроизведения (Sample Rate, Mono/Stereo, PAL/NTSC, скорость, фильтры, панорамирование каждого канала, отключение отдельных чипов и т.д.)

Я все планировал сделать сам и результат выложить сюда, но учитывая отсутствие опыта какого-то серьезного программирования на C++ и отсутствие примеров с исходниками плагинов-декодеров на C++, возникли проблемки.

На данный момент плагин успешно подключается к AIMP4, пропускает мимо все неподдерживаемые файлы, а поддерживаемые успешно загружает в ядро NSF декодера. И вроде все готово для генерации PCM-семплов в буфер AIMP посредством вызова  AIMPAudioDecoder::Read(), но до этого дело не доходит. В отладчике можно увидеть, что при попытке воспроизведения подходящего файла AIMP создает декодер (CAIMPNSFDecoderExtension::CreateDecoder), затем запрашивает всякую информацию о потоке, затем несколько раз вызывает GetAvailableData() и валится с ошибкой:
Quote
Вызвано исключение по адресу 0x62EF4BCF (AIMP.Shared.dll) в AIMP.exe: 0xC0000005: нарушение прав доступа при чтении по адресу 0xDDDDDE01

На текущем этапе задача – просто заставить AIMP проиграть NSF-файл с параметрами, например, 2 минуты трек, 48KHz, 2 канала, 16 бит на семпл. Поэтому все это захардкожено и IsSeekable() возвращает false. Как решим эту ошибку – буду делать нормальный встроенный диалог со всеми настройками.
Скорее всего где-то в классе декодера допустил глупую ошибку, прошу указать на нее.

Исходники оригинального NotSo Fatso v0.851: http://slickproductions.org/programs/NotSoFatso/NotSoFatso_v851_src.tar.gz (информация (http://slickproductions.org/notsofatso.php))
Исходники моей попытки портирования во вложениях.
В оригинальные исходники были внесены необходимые изменения для компиляции современным компилятором, в остальном они не тронуты.
В каталоге AIMPSDK официальный SDK и некоторые обертки над ним, от которых в последствии было решено отказаться.
В AIMP.cpp, AIMP.h весь код для AIMP. Проект собирается в Visual Studio 2017, должен собираться и в 2015 и в более ранних.
Структуру оригинальных исходников см. в авторском Readme.txt (там в том числе указано как работать с ядром NSF_Core)

Моя версия AIMP: 4.13, build 1895
Контрольная сумма AIMP.Shared.dll (SHA1): 3343E07446E63FF11630902D442664FCC495BD06
Title: Re: Нужна помощь в портировании input плагина NotSo Fatso от Winamp (C++)
Post by: ugubok on June 23, 2017, 10:03:48
Тут в архиве однотрековый NSF и мультитрековый NSFE.
Title: Re: Нужна помощь в портировании input плагина NotSo Fatso от Winamp (C++)
Post by: Artem on June 23, 2017, 10:08:21
Нашел у себя опечатку в коде IAIMPExtensionFileFormat, должно быть так:

Code: [Select]
virtual HRESULT WINAPI GetFlags(DWORD *S) = 0;

AV при закрытии плеера, удалять объекты fileFormat и DecoderExtension не нужно:

Code: [Select]
HRESULT WINAPI CAIMPNSFPlugin::Finalize()
{
decoderExtension->Release();
fileformat->Release();
aimpCore->Release();
aimpCore = nullptr;
return S_OK;
}

Опечатка у вас в коде:

Code: [Select]
BOOL CAIMPNSFDecoder::GetStreamInfo(int * SampleRate, int * Channels, int * SampleFormat)
{
*SampleRate = 48000;
*Channels = 2;
*SampleFormat = AIMP_DECODER_SAMPLEFORMAT_16BIT;
return true; <<< MUST BE TRUE
}

А вот, собственно, и причина - объект убивался раньше времени:
Code: [Select]
HRESULT CAIMPNSFDecoderExtension::CreateDecoder(IAIMPStream * Stream, DWORD Flags, IAIMPErrorInfo * ErrorInfo, IAIMPAudioDecoder ** Decoder)
{
int bCreatedSuccessfully;
CAIMPNSFDecoder* decoder = new CAIMPNSFDecoder(Stream, aimpCore, &bCreatedSuccessfully);

if (bCreatedSuccessfully)
{
*Decoder = decoder;
decoder->AddRef(); <<<< LINE ADDED
return S_OK;
}
else return E_FAIL;  // Cannot initialise NSF Core or load NSF file (not enough memory or wrong file)
// TODO: Fill ErrorInfo structure, detect what fails: core or file
}
[code]

P.S. Я за это и не люблю С++ - он слишком низкоуровневый, вот такие вещи упустить очень легко, а найти - сложно.
Title: Re: Нужна помощь в портировании input плагина NotSo Fatso от Winamp (C++)
Post by: Artem on June 23, 2017, 10:09:28
И кстати, спасибо большое за плагин.
Title: Re: Нужна помощь в портировании input плагина NotSo Fatso от Winamp (C++)
Post by: ugubok on June 23, 2017, 12:09:26
Спасибо за помощь, теперь управление доходит до Read! Но ядро NSF заполняет буфер нулями, сейчас разбираюсь в чем причина.

UPD
Разобрался, теперь плагин играет. На днях продолжу с диалогом настроек и прочим, результат как и обещал выложу сюда или в новую тему.

P.S. Можно ли как-то мультитрековые файлы добавлять в плейлист в виде нескольких треков (например как в случае с FLAC)? Как это лучше сделать? (Знаю, мог бы сам докопаться до этого в справке, но решил тут спросить чтоб не тратить время на решение глупых проблем из-за каких-то неучтенных тонкостей)
...
И еще вопрос, как лучше освобождать экземпляр декодера? Память течет неимоверно. Думаю это нужно делать когда трек закончился, хорошее ли это решение?