а есть нетлист симулятор для AY?
ZXMAK2 - Виртуальная Машина ZX Spectrum https://github.com/zxmak/ZXMAK2 (старая ссылка http://zxmak2.codeplex.com)
ZXMAK.NET - спектрум на C# http://sourceforge.net/projects/zxmak-dotnet
Настолько лень гуглить?
https://github.com/lvd2/ay-3-8910_reverse_engineered
ZXMAK(06.04.2025)
ZXMAK, Вот чудесам нет предела, ты напоминаешь мне чат-робота (DeepSeek) - попросил wav послушать - накидано чёрт-те что, ну я прям восхищён...
Ладно, по случаю откомпилю, вдруг да прозвучит что-то...
(и что за ересь PSG такое... я походу лихо отстал в звукогенерации, это попахивает вообще линухами, а не дай боже ещё и крэями...)
Ох обленился, пора снова грызть теорию (думал на пенсию выйду - буду облизывать кванты-бозоны-немножечко лептонов, ан вот тут со звукообразованием затык)
ещë мысля таблички хранить в 8 бит, а по мере воспроизведения дробить на полубайты, и посылать туда и туда на два разных канала.
8 бит ЦАП. Правда логарифмическое искажение получится двухкратное... а может есть готовые решения, где wav конаертится в 8 бит на два канала AY ? Или всем влом таким маяться?
- - - Добавлено - - -
Ещë вариант - остаться на 4ëх битах, но использовать по два старших на двух разных каналах, тем самым минимизировав разброс напряжений.
- - - Добавлено - - -
дажы ни знаю, какой варик лутшы...
FLAC - это тот-же WAV но со сжатием без потерь, правда поддерживает только целочисленный формат сэмплов и не все частоты дискретизации, но зато в 2 раза меньше места на диске занимает и использует сжатие без потерь, т.е. что записал, то в точности и прочитается - без искажений сигнала. У меня диск всего 64 GB, из них только 15 свободно, поэтому использую FLAC вместо WAV, где возможно. Звуковые редакторы и плееры его понимают на всех платформах, поэтому проблем быть не должно.
PSG - это старый формат, грубо говоря лог записей в регистры AY, что удобно для воспроизведения без необходимости эмуляции Z80. В этом формате часто музыку для AY выкладывают. Был доступен еще в эмуляторе x128 и Z80Stealth:
Код:PSG These files are produced by 'x128' Speccy Emulator by James McKey and 'fMSX' emulator (I never saw this one). x128 creates PSG with errors. Therefore more better to use 'Z80 Stealth' Speccy Emulator by Kirill Kolpakov (Mr.Kirill). This emulator contains special features for creating PSG files and also has good debugger which very simplifies PSG creating process. Z80 Stealth Home Page is http://z80.da.ru. This is all data about PSG found in Internet: Offset Number of byte Description +0 3 Identifier 'PSG' +3 1 Marker “End of Text” (1Ah) +4 1 Version number +5 1 Player frequency (for versions 10+) +6 10 Unknown Further byte strings follows. Each string begins from byte 0FFh or 0FEh. Byte 0FFh is marker of interrupt beginning. If after it byte exists (in range 0–15) then it is number of AY register, and next byte is value of this register. Further next pair of byte follows, first byte of which is register number, and second byte is register value. And so on, until end of file, or byte 0FFh (next interrupt), or byte 0FEh will be meet. Byte after 0FEh marker is multiplied by four is number of interrupts without outing to AY. For example sequence “FE 01 FF” is equivalent to sequence “FF FF FF FF FF”. If in PSG you will find register number in range 16–252, then you can ignore this and next byte (this is outing to other MSX devices). RDOSPLAY documentation describes yet another marker is 253 called as 'End Of Music', but this marker is not supported in Emulator. Also, RDOSPLAY documentation and some my researching of existing PSG-files talk about is more simple header of PSG. This header consists of only first 4 bytes of described header and outing log starts at +4 file offset (instead of +16). So, for correct playing this PSG, need to add zero to expanse header size to 16 bytes length. If you are trying to play such PSG-files without header correcting, you don't hear differences in the most cases. EPSG Z80 Stealth emulator creates these files. EPSG additionally contents information about time of outing to AY registers. Next text from z80s.faq file. Q: What is it – this EPSG format? A: It's PSG format improved just a bit to handle output of digitized samples Here's the description: Offset Length Value ============================ Header ============================ 0 4 'EPSG' 4 1 0x1A marker 5 1 Machine type: 0x00 – ZX Spectrum 128 0x01 – Pentagon 0xFF – Other machines 6 4 Zero for machine type 0x00 and 0x01 or Number of Z80 tacts between interrupt markers for other machines 10 6 zeroes ============================ AY(YM) log during 1 frame ============================ 16 1 AY(YM) register number 17 1 value written to this register 18 3 T-state ..... ?? 5 0xFFFFFFFFFF – interrupt marker
Последний раз редактировалось ZXMAK; 09.04.2025 в 02:29.
ZXMAK2 - Виртуальная Машина ZX Spectrum https://github.com/zxmak/ZXMAK2 (старая ссылка http://zxmak2.codeplex.com)
ZXMAK.NET - спектрум на C# http://sourceforge.net/projects/zxmak-dotnet
С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
вот набросал MATLAB/Octave скрипт для конвертации wav/flac в бинарник, где 1 байт это 2 сэмпла для левого и правого канала, с учетом логарифмического масштабирования. Скрипт также читает созданный файл и производит обратное преобразование во flac, чтобы послушать что получилось. Результаты не очень - искажения сильнее, чем на 4 битном ЦАП-е. Как улучшить не знаю, может кто другой подскажет...
- - - Добавлено - - -Код:if exist('OCTAVE_VERSION', 'builtin') pkg load signal; end folderOut = '/dev/shm/OCTAVE'; if ~exist(folderOut, 'dir') mkdir(folderOut); end fileNameIn = 'TEST/test.flac'; fileNameBin = 'test-ay-%d.bin'; % %d will be replaced with sample rate fileNameOut = 'test-ay.flac'; if 0 % YM2149 volume table (taken from emulator) x = [0x0000,0x0000,0x00EF,0x01D0,0x0290,0x032A,0x03EE,0x04D2,... 0x0611,0x0782,0x0912,0x0A36,0x0C31,0x0EB6,0x1130,0x13A0,... 0x1751,0x1BF5,0x20E2,0x2594,0x2CA1,0x357F,0x3E45,0x475E,... 0x5502,0x6620,0x7730,0x8844,0xA1D2,0xC102,0xE0A2,0xFFFF]; else % AY8910 volume table (taken from emulator) x = [0x0000,0x0340,0x04C0,0x06F2,... 0x0A44,0x0F13,0x1510,0x227E,... 0x289F,0x414E,0x5B21,0x7258,... 0x905E,0xB550,0xD7A0,0xFFFF]; end y = 0:(length(x)-1); x = double(x); y = double(y); % normalize to 0..1 range x = x / max(x); y = y / max(y); % remove duplicated values [x, unique_idx] = unique(x); y = y(unique_idx); % read wave [signal, Fs] = audioread(fileNameIn); % get first 5 seconds signal = signal(1:(Fs*5), :); if 0 % change sample rate from Fs to Fs2 Fs2 = 24000; signal = resample(signal, Fs2, Fs); Fs = Fs2; end % split L and R channels signal_l = double(signal(:,1)'); signal_r = double(signal(:,2)'); % gain normalization peak = max(max(abs(signal_l)), max(abs(signal_r))); signal_l = signal_l / peak; signal_r = signal_r / peak; if min(signal_l) < -1 || max(signal_l) > 1 || min(signal_r) < -1 || max(signal_r) > 1 fprintf('warn stage w0: min-l: %g, max-l: %g, min-r: %g, max-r: %g\n', min(signal_l), max(signal_l), min(signal_r), max(signal_r)); end % scale to 0..+1 signal_l = (1+signal_l) / 2; signal_r = (1+signal_r) / 2; if min(signal_l) < 0 || max(signal_l) > 1 || min(signal_r) < 0 || max(signal_r) > 1 fprintf('warn stage w1: min-l: %g, max-l: %g, min-r: %g, max-r: %g\n', min(signal_l), max(signal_l), min(signal_r), max(signal_r)); end % scale from linear to AY signal_l = spline(x, y, signal_l); signal_r = spline(x, y, signal_r); if min(signal_l) < 0 || max(signal_l) > 1 || min(signal_r) < 0 || max(signal_r) > 1 fprintf('warn stage w2: min-l: %g, max-l: %g, min-r: %g, max-r: %g\n', min(signal_l), max(signal_l), min(signal_r), max(signal_r)); signal_l = min(1, max(0, signal_l)); signal_r = min(1, max(0, signal_r)); end signal_l = round(signal_l * 15); signal_r = round(signal_r * 15); if min(signal_l) < 0 || max(signal_l) > 15 || min(signal_r) < 0 || max(signal_r) > 15 fprintf('warn stage w3: min-l: %g, max-l: %g, min-r: %g, max-r: %g\n', min(signal_l), max(signal_l), min(signal_r), max(signal_r)); end % combine L and R channels into byte signal_8 = bitshift(signal_r, 4) + signal_l; if min(signal_8) < 0 || max(signal_8) > 255 fprintf('warn stage w4: min: %g, max: %g\n', min(signal_8), max(signal_8)); end % write result fid = fopen(fullfile(folderOut, sprintf(fileNameBin, Fs)), 'wb'); fwrite(fid, signal_8, 'uint8'); fclose(fid); %----------------------------------------------------------------------- % read and convert to wav % read back fid = fopen(fullfile(folderOut, sprintf(fileNameBin, Fs)), 'rb'); signal_8 = fread(fid, 'uint8'); fclose(fid); % restore L and R channels from byte signal_l = bitand(signal_8, 15); signal_r = bitshift(signal_8, -4); signal_l = signal_l / 15; signal_r = signal_r / 15; if min(signal_l) < 0 || max(signal_l) > 1 || min(signal_r) < 0 || max(signal_r) > 1 fprintf('warn stage r0: min-l: %g, max-l: %g, min-r: %g, max-r: %g\n', min(signal_l), max(signal_l), min(signal_r), max(signal_r)); end % scale back from AY to linear signal_l = spline(y, x, signal_l); signal_r = spline(y, x, signal_r); if min(signal_l) < 0 || max(signal_l) > 1 || min(signal_r) < 0 || max(signal_r) > 1 fprintf('warn stage r1: min-l: %g, max-l: %g, min-r: %g, max-r: %g\n', min(signal_l), max(signal_l), min(signal_r), max(signal_r)); signal_l = min(1, max(0, signal_l)); signal_r = min(1, max(0, signal_r)); end % scale to -1..+1 signal_l = signal_l*2 - 1; signal_r = signal_r*2 - 1; if min(signal_l) < -1 || max(signal_l) > 1 || min(signal_r) < -1 || max(signal_r) > 1 fprintf('warn stage r2: min-l: %g, max-l: %g, min-r: %g, max-r: %g\n', min(signal_l), max(signal_l), min(signal_r), max(signal_r)); end signal = [signal_l signal_r]; if Fs > 48000 signal = resample(signal, 48000, Fs); Fs = 48000; end % write result audiowrite(fullfile(folderOut, fileNameOut), signal, Fs, 'BitsPerSample', 16);
хм, если заменить табличку громкости на вариант от AY8910 (с 16 уровнями), то результат заметно лучше. Видимо результат зависит от линейности используемой кривой.
Update: обновил скрипт, исправил ошибку.
Думаю если поиграть с табличкой уровней, то можно еще лучше результат получить, но нужно пробовать как на самом AY будет звучать.
Вот пример что получилось: https://transfiles.ru/asd3e
FLAC - это то как это по идее должно звучать на AY, а bin - это бинарный файл, где младшие 4 бита - это AY громкость для левого канала, старшие 4 бита- это AY громкость для правого канала.
В идеале конечно лучше померять реальную амплитуду на выходе AY и обновить таблички, это по идее даст более качественный сигнал, т.к. позволит уменьшить нелинейные искажения сигнала.
Последний раз редактировалось ZXMAK; 09.04.2025 в 12:40.
ZXMAK2 - Виртуальная Машина ZX Spectrum https://github.com/zxmak/ZXMAK2 (старая ссылка http://zxmak2.codeplex.com)
ZXMAK.NET - спектрум на C# http://sourceforge.net/projects/zxmak-dotnet
ALKO(12.08.2025)
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)