Похоже на то, что спектрумовские мелодии навсегда останутся в моём сердце, так как я регулярно слушаю любимые композиции, используя замечательный бульбовский проигрыватель.
Но не очень удобно быть привязанным к компьютеру. Эту проблему я временно решал, используя не менее замечательный EEE PC. Но хотелось ещё большей миниатюрности.
Поиски в интернете привели на следующих красавцев:
Они восхитительны своей элементной базой, которая вызывает ностальгические воспоминания, но я понимал, что моя лень не позволит мне довести такой проект до конца.
Мне нужно было что-то небольшое. И вот — практически идеальный кандидат:
AVR AY-player
— играет файлы *.PSG
— поддерживаемая файловая система FAT16
— количество каталогов в корне диска 32
— количество файлов в каталоге 42 (итого 32*42=1344 файлов)
— сортировка каталогов и файлов в каталогах по первым двум буквам имени
Схема выглядит весьма приемлемой по размеру:
Конечно же нашёлся фатальный недостаток, который портил идиллию: нет режима случайного выбора композиции. (возможно стоило просто попросить автора добавить эту функцию в прошивку?).
Джва года я искал подходящий вариант, моё терпение кончилось и я решил действовать.
Исходя из моей фантастической лени, я выбрал минимальные телодвижения:
1. Берём Arduino Mini Pro, чтобы не возится с обвязкой.
2. Нужна SD-карта, чтобы где-то хранить музыку. Значит берём SD-shield.
3. Нужен музыкальный сопроцессор. Самый маленький — AY-3-8912.
Был ещё вариант сэмулировать сопроцессор программным путём, но хотелось «тёплого лампового звука», евпочя.
Для воспроизведения будем использовать PSG-формат.
+0 3 Identifier 'PSG'
+3 1 Marker “End of Text” (1Ah)
+4 1 Version number
+5 1 Player frequency (for versions 10+)
+6 10 Data
Data — последовательности пар байтов записи в регистр.
Первый байт — номер регистра (от 0 до 0x0F), второй — значение.
Вместо номера регистра могут быть специальные маркеры: 0xFF, 0xFE или 0xFD
0xFD — конец композиции.
0xFF — ожидание 20 мс.
0xFE — следующий байт показывает сколько раз выждать по 80 мс.
2. Открываем плейлист кнопкой [PL].
3. Добавляем мелодии в плейлист.
4. Выбираем мелодию в списке, правой кнопкой вызываем меню, в нём Convert to PSG...
5. Сохраняем желательно под именем не длиннее 8 символов, иначе оно будет отображено не полнос~1.тью.
Начнём с подключения SD-карты. Лень подсказала взять стандартное подключение SD-shield и использовать стандартную библиотеку для работы с картой.
Единственное отличие — для удобства использовал 10 вывод в качестве сигнала выбора карты:
Для проверки берём стандартный скетч:
#include <SPI.h>
#include <SD.h>
void setup() {
Serial.begin(9600);
Serial.print("Initializing SD card...");
if (!SD.begin(10)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
File root = SD.open("/");
printDirectory(root);
Serial.println("done!");
}
void loop() {
}
void printDirectory(File dir) {
while (true) {
File entry = dir.openNextFile();
if (!entry) break;
Serial.print(entry.name());
if (!entry.isDirectory()) {
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
Форматируем карту, пишем туда несколько файлов, запускам… не работает!
Вот у меня так всегда — наистандартнейшая задача — и сразу косяки.
Берём другую флешку — (была старенькая на 32Mb, берём новенькую на 2Gb) — ага, заработало, но через раз. Полчаса чесания лба, перестановка соединений поближе к карте (чтобы проводники были короче), развязочный конденсатор по питанию — и работать стало в 100% случаев. Ладно, едем дальше…
Теперь надо завести сопроцессор — ему нужна тактовая частота 1.75 МГц. Вместо того, чтобы спаять генератор на 14 МГц кварце и поставить делитель, тратим полдня на чтение доков по микроконтроллеру и узнаём, что можно сделать хардовые 1.77(7) МГц, используя быстрый ШИМ:
pinMode(3, OUTPUT);
TCCR2A = 0x23;
TCCR2B = 0x09;
OCR2A = 8;
OCR2B = 3;
Далее, заводим сброс музсопроцессора на пин 2, нижний ниббл шины данных на A0-A3, верхний на 4,5,6,7, BC1 на пин 8, BDIR на пин 9. Аудио выходы для простоты подключим в моно режиме:
На макетке:
void resetAY(){
pinMode(A0, OUTPUT); // D0
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT); // D3
pinMode(4, OUTPUT); // D4
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT); // D7
pinMode(8, OUTPUT); // BC1
pinMode(9, OUTPUT); // BDIR
digitalWrite(8,LOW);
digitalWrite(9,LOW);
pinMode(2, OUTPUT);
digitalWrite(2, LOW);
delay(100);
digitalWrite(2, HIGH);
delay(100);
for (int i=0;i<16;i++) ay_out(i,0);
}
void setupAYclock(){
pinMode(3, OUTPUT);
TCCR2A = 0x23;
TCCR2B = 0x09;
OCR2A = 8;
OCR2B = 3;
}
void setup() {
setupAYclock();
resetAY();
}
void ay_out(unsigned char port, unsigned char data){
PORTB = PORTB & B11111100;
PORTC = port & B00001111;
PORTD = PORTD & B00001111;
PORTB = PORTB | B00000011;
delayMicroseconds(1);
PORTB = PORTB & B11111100;
PORTC = data & B00001111;
PORTD = (PORTD & B00001111) | (data & B11110000);
PORTB = PORTB | B00000010;
delayMicroseconds(1);
PORTB = PORTB & B11111100;
}
unsigned int cb = 0;
byte rawData[] = {
0xFF, 0x00, 0x8E, 0x02, 0x38, 0x03, 0x02, 0x04, 0x0E, 0x05, 0x02, 0x07,
0x1A, 0x08, 0x0F, 0x09, 0x10, 0x0A, 0x0E, 0x0B, 0x47, 0x0D, 0x0E, 0xFF,
0x00, 0x77, 0x04, 0x8E, 0x05, 0x03, 0x07, 0x3A, 0x08, 0x0E, 0x0A, 0x0D,
0xFF, 0x00, 0x5E, 0x04, 0x0E, 0x05, 0x05, 0x0A, 0x0C, 0xFF, 0x04, 0x8E,
0x05, 0x06, 0x07, 0x32, 0x08, 0x00, 0x0A, 0x0A, 0xFF, 0x05, 0x08, 0x0A,
0x07, 0xFF, 0x04, 0x0E, 0x05, 0x0A, 0x0A, 0x04, 0xFF, 0x00, 0x8E, 0x04,
0x8E, 0x05, 0x00, 0x07, 0x1E, 0x08, 0x0F, 0x0A, 0x0B, 0x0D, 0x0E, 0xFF,
0x00, 0x77, 0x08, 0x0E, 0x0A, 0x06, 0xFF, 0x00, 0x5E, 0x07, 0x3E, 0x0A,
0x00, 0xFF, 0x07, 0x36, 0x08, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x8E, 0x07,
0x33, 0x08, 0x0B, 0x0A, 0x0F, 0x0D, 0x0E, 0xFF, 0x04, 0x77, 0x08, 0x06,
0x0A, 0x0E, 0xFF, 0x04, 0x5E, 0x07, 0x3B, 0x08, 0x00, 0xFF, 0x07, 0x1B,
0x0A, 0x00, 0xFF, 0xFF, 0xFF, 0x02, 0x1C, 0x03, 0x01, 0x04, 0x8E, 0x07,
0x33, 0x08, 0x0B, 0x0A, 0x0B, 0x0B, 0x23, 0x0D, 0x0E, 0xFF, 0x04, 0x77,
0x08, 0x06, 0x0A, 0x0A, 0xFF, 0x04, 0x5E, 0x07, 0x3B, 0x08, 0x00, 0x0A,
0x09, 0xFF, 0x07, 0x1B, 0x0A, 0x00, 0xFF, 0xFF, 0xFF, 0x02, 0x8E, 0x03,
0x00, 0x04, 0x0E, 0x05, 0x01, 0x07, 0x18, 0x08, 0x0F, 0x09, 0x0B, 0x0A,
0x0E, 0xFF, 0x00, 0x77, 0x02, 0x77, 0x04, 0x8E, 0x06, 0x01, 0x08, 0x0E,
0x09, 0x0A, 0x0A, 0x0D, 0xFF, 0x00, 0x5E, 0x02, 0x5E, 0x04, 0x0E, 0x05,
0x02, 0x06, 0x02, 0x09, 0x09, 0x0A, 0x0C, 0xFF, 0x02, 0x8E, 0x04, 0x8E,
0x07, 0x30, 0x08, 0x00, 0x09, 0x08, 0x0A, 0x0A, 0xFF, 0x02, 0x77, 0xFF,
0xFF
}
void pseudoInterrupt(){
while (rawData[cb]<0xFF) {
ay_out(rawData[cb],rawData[cb+1]);
cb++;
cb++;
}
if (rawData[cb]==0xff) cb++;
if (cb>20*12) cb=0;
}
void loop() {
delay(20);
pseudoInterrupt();
}
И слышим полсекунды какой-то прекрасной мелодии! (на самом деле я тут ещё два часа ищу как я забыл отпустить ресет после инициализации).
На этом железная часть закончена, а в программной добавляем прерывания 50 Гц, считывание файла и запись в регистры сопроцессора.
#include <SPI.h>
#include <SD.h>
void resetAY(){
pinMode(A0, OUTPUT); // D0
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT); // D3
pinMode(4, OUTPUT); // D4
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT); // D7
pinMode(8, OUTPUT); // BC1
pinMode(9, OUTPUT); // BDIR
digitalWrite(8,LOW);
digitalWrite(9,LOW);
pinMode(2, OUTPUT);
digitalWrite(2, LOW);
delay(100);
digitalWrite(2, HIGH);
delay(100);
for (int i=0;i<16;i++) ay_out(i,0);
}
void setupAYclock(){
pinMode(3, OUTPUT);
TCCR2A = 0x23;
TCCR2B = 0x09;
OCR2A = 8;
OCR2B = 3;
}
void setup() {
Serial.begin(9600);
randomSeed(analogRead(4)+analogRead(5));
initFile();
setupAYclock();
resetAY();
setupTimer();
}
void setupTimer(){
cli();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 1250;
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS12);
TIMSK1 |= (1 << OCIE1A);
sei();
}
void ay_out(unsigned char port, unsigned char data){
PORTB = PORTB & B11111100;
PORTC = port & B00001111;
PORTD = PORTD & B00001111;
PORTB = PORTB | B00000011;
delayMicroseconds(1);
PORTB = PORTB & B11111100;
PORTC = data & B00001111;
PORTD = (PORTD & B00001111) | (data & B11110000);
PORTB = PORTB | B00000010;
delayMicroseconds(1);
PORTB = PORTB & B11111100;
}
unsigned int playPos = 0;
unsigned int fillPos = 0;
const int bufSize = 200;
byte playBuf[bufSize]; // 31 bytes per frame max, 50*31 = 1550 per sec, 155 per 0.1 sec
File fp;
boolean playFinished = false;
void loop() {
fillBuffer();
if (playFinished){
fp.close();
openRandomFile();
playFinished = false;
}
}
void fillBuffer(){
int fillSz = 0;
int freeSz = bufSize;
if (fillPos>playPos) {
fillSz = fillPos-playPos;
freeSz = bufSize - fillSz;
}
if (playPos>fillPos) {
freeSz = playPos - fillPos;
fillSz = bufSize - freeSz;
}
freeSz--; // do not reach playPos
while (freeSz>0){
byte b = 0xFD;
if (fp.available()){
b = fp.read();
}
playBuf[fillPos] = b;
fillPos++;
if (fillPos==bufSize) fillPos=0;
freeSz--;
}
}
void prepareFile(char *fname){
Serial.print("prepare [");
Serial.print(fname);
Serial.println("]...");
fp = SD.open(fname);
if (!fp){
Serial.println("error opening music file");
return;
}
while (fp.available()) {
byte b = fp.read();
if (b==0xFF) break;
}
fillPos = 0;
playPos = 0;
cli();
fillBuffer();
resetAY();
sei();
}
File root;
int fileCnt = 0;
void openRandomFile(){
int sel = random(0,fileCnt-1);
Serial.print("File selection = ");
Serial.print(sel, DEC);
Serial.println();
root.rewindDirectory();
int i = 0;
while (true) {
File entry = root.openNextFile();
if (!entry) break;
Serial.print(entry.name());
if (!entry.isDirectory()) {
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
if (i==sel) prepareFile(entry.name());
i++;
}
entry.close();
}
}
void initFile(){
Serial.print("Initializing SD card...");
pinMode(10, OUTPUT);
digitalWrite(10, HIGH);
if (!SD.begin(10)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
root = SD.open("/");
// reset AY
fileCnt = countDirectory(root);
Serial.print("Files cnt = ");
Serial.print(fileCnt, DEC);
Serial.println();
openRandomFile();
Serial.print("Buffer size = ");
Serial.print(bufSize, DEC);
Serial.println();
Serial.print("fillPos = ");
Serial.print(fillPos, DEC);
Serial.println();
Serial.print("playPos = ");
Serial.print(playPos, DEC);
Serial.println();
for (int i=0; i<bufSize;i++){
Serial.print(playBuf[i],HEX);
Serial.print("-");
if (i%16==15) Serial.println();
}
Serial.println("done!");
}
int countDirectory(File dir) {
int res = 0;
root.rewindDirectory();
while (true) {
File entry = dir.openNextFile();
if (!entry) break;
Serial.print(entry.name());
if (!entry.isDirectory()) {
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
res++;
}
entry.close();
}
return res;
}
int skipCnt = 0;
ISR(TIMER1_COMPA_vect){
if (skipCnt>0){
skipCnt--;
} else {
int fillSz = 0;
int freeSz = bufSize;
if (fillPos>playPos) {
fillSz = fillPos-playPos;
freeSz = bufSize - fillSz;
}
if (playPos>fillPos) {
freeSz = playPos - fillPos;
fillSz = bufSize - freeSz;
}
boolean ok = false;
int p = playPos;
while (fillSz>0){
byte b = playBuf[p];
p++; if (p==bufSize) p=0;
fillSz--;
if (b==0xFF){ ok = true; break; }
if (b==0xFD){
ok = true;
playFinished = true;
for (int i=0;i<16;i++) ay_out(i,0);
break;
}
if (b==0xFE){
if (fillSz>0){
skipCnt = playBuf[p];
p++; if (p==bufSize) p=0;
fillSz--;
skipCnt = 4*skipCnt;
ok = true;
break;
}
}
if (b<=252){
if (fillSz>0){
byte v = playBuf[p];
p++; if (p==bufSize) p=0;
fillSz--;
if (b<16) ay_out(b,v);
}
}
} // while (fillSz>0)
if (ok){
playPos = p;
}
} // else skipCnt
}
Для полной автономности я ещё добавил усилитель на TDA2822M, сам проигрыватель потребляет 90 мА, вместе с усилителем — около 200 мА, при желании можно питать от аккумуляторов.
Обе макетки вместе:
Вот на этом этапе я пока остановился, музыку слушаю с макетки, раздумываю в каком корпусе я бы хотел это собрать. Думал подключить индикатор, но необходимости как-то не испытываю.
Реализация пока сыровата, т.к. устройство в состоянии разработки, но т.к. я могу его забросить на пару лет в таком состоянии, решил написать статью по горячим следам. Вопросы, предложения, замечания, исправления — приветствую в комментариях.
Использованная литература:
- Generating 1-4 MHz clock on Arduino
- Playing chiptunes with a YM2149 and optimizing an Arduino
- YM2149 sound generator, Arduino and fast pin switching
- ZX Spectrum AY adapter
- Олдскул, хардкор, AY-3-8912. «Железный» чиптюн с последовательным входом
- Звук на чипе AY-3-8910 (или Yamaha YM2149F) родом с ZX Spectrum на PC через LPT-порт
- Самодельный SD Card Shield для Arduino
- Software AY players
- AY38910 controlled by Arduino — Basic connections
- Эмулятор AY на Arduino
- Проигрываель AY на AVR Atmega8 [ASM/Algorithm Builder]
Комментарии (53)
dlinyj
07.04.2016 12:02Вот что-то подобное я очень хотел.
Однако, опять же что-то сырое. Хочу автономный плеер. Тёплый и ламповый :)Z80A
07.04.2016 12:15+1Сырое, но работает. Автономный, тёплый и ламповый, что не так-то?
dlinyj
07.04.2016 12:30Пока устройство не имеет корпуса и не используется, значит устройства нет. Я уже писал об этом.
geektimes.ru/post/257212Z80A
07.04.2016 12:39+1Спасибо, теперь понятно. Но я не разделяю вашу точку зрения.
Я делаю корпус из того, что под руку придётся, это сильно экономит время.
Вот например моё готовое устройство RFID-сканер:
dlinyj
07.04.2016 12:41Крутое устройство, респект. Что внутрях? Я тоже делал такую читалку.
Не важно из чего и как делается. Важно, чтобы устройство было не на соплях на столе, а законченным.Z80A
07.04.2016 12:50Arduino+RDM6300. Планировал копировщик, но случайно собрал на другой базе (в другом корпусе собран), поэтому пока остался ридером. Как скучно будет — допилю копирование.
dlinyj
07.04.2016 12:57У меня приятель сделал пассивный эмулятор таких меток на AVR.
Можно было не вешать ещё одну платку, а сделать всё на АВР. Я делал.Z80A
07.04.2016 13:00Поделишься исходниками твоего проекта на AVR? Я бы много времени сэкономил.
dlinyj
07.04.2016 13:04Которого, эмуля или ридера? Ридер постараюсь найти, но с кучей переездом и прочим могли пролюбится. А вот эмуль найду.
Z80A
07.04.2016 13:07Давай в личку, а то какой-то оффтоп пошёл?
dlinyj
07.04.2016 13:08Может в этом офтопе кто-то найдёт для себя что-то полезное. После обеда всё скину сюда.
Z80A
07.04.2016 13:10Хорошо. Софтовый ридер интереснее, чем эмуль, но кидай всё, что не жалко.
dlinyj
07.04.2016 13:34+1Вот сам эмулятор (то с чего мы начинали).
Сишный код#include <avr/io.h> #include <avr/sfr_defs.h> #include <compat/ina90.h> #include <avr/interrupt.h> #include <stdlib.h> #include <avr/sleep.h> #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif volatile int bit_counter=0; volatile int byte_counter=0; volatile int half=0; unsigned char data_card[5][8] = {{0xFF,0xC5,0x38,0x2D,0x19,0xD1,0xC9,0x5A}, //test {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, // other cards {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}}; unsigned char data[8]; void delay_ms(int ms) { // 1.000 MHz int i; for (i=0; i < ms; i++) { TCNT0=0; while (TCNT0 < 125); } } ISR(SIG_OUTPUT_COMPARE1A){ TCNT1=0; // if(byte_counter==0) sbi(PORTB,PD1); // else cbi(PORTB,PD1); if (((data[byte_counter] << bit_counter)&0x80)==0x00) { if (half==0) cbi(PORTB,PB1); if (half==1) sbi(PORTB,PB1); } else { if (half==0) sbi(PORTB,PB1); if (half==1) cbi(PORTB,PB1); } half++; if (half==2) { half=0; bit_counter++; if (bit_counter==8) { bit_counter=0; byte_counter=(byte_counter+1)%8; } } } int main(void) { int i; DDRB=0xFF; DDRC=0x00; DDRD=0x00; PORTC=0x00; TCCR0 = 2; // timer0 clock/8 // TCCR1B = 2; // timer1 clock/8 TCCR1B = 3; // OCR1A = 254; // OCR1A = 32; //32 unsigned char sel = (PINC >> 1) & 0x07; OCR1A = 30 + sel; // for (i=0;i<8;i++) data[i]=data_card[sel][i]; for (i=0;i<8;i++) data[i]=data_card[0][i]; sbi(TIMSK, OCIE1A); // timer1 Output Compare A match sei(); while (1) { } return 0; }
dlinyj
07.04.2016 13:40+1ww1.microchip.com/downloads/en/AppNotes/00680b.pdf — отличная пдф-ка о расчётах антенн.
Мой эмулятор выглядел вот так
Антенну считал и мотал к нему по мануалу. В ЖЖ можно найти описание как я это делал.
Собственно говоря делался по этому мануалу
Камрад из Германии скрестил эти два проекта и получил такую петрушку
Нашёл таки его сайт www.alexanderguthmann.de/en/emulator.html
Инфы море, поэтому можно пошерстить мой ЖЖ по тегу dlinyj.livejournal.com/tag/rfid (там много страниц).dlinyj
07.04.2016 13:56+2Не ту пдф-ку скинул :(.
www.meraprojekt.com.pl/files/AN411.pdf вот она.
Больше всего доставляет картинка в документации
Syzd
07.04.2016 12:10«развязочный конденсатор по питанию — и работать стало в 100% случаев. Ладно, едем дальше…» поясните пожалйста схемой что сделали. А то тоже требовалось читать с SD карты. Вдруг решит проблему.
Z80A
07.04.2016 12:26+1Все выводы питания SD-карты и ардуино собрал как можно ближе друг к другу и в этом месте поставил конденсатор 10 микрофарад:
dlinyj
07.04.2016 12:31Ещё хорошо поставить керамику 0,1 мкФ
Z80A
07.04.2016 12:32+1Если посмотреть на фото макетки, то она там стоит чуть левее, ближе к сопру, чтобы по звуку было меньше помех.
dlinyj
07.04.2016 12:35Я просто комментатору отметил, чтобы он имел это в виду.
Когда я был мелкий, то экономил на кондёрах по питанию. В результате всегда имел много весёлых граблей :)))Z80A
07.04.2016 12:56+1Просто натыкать 0.1 не всегда полезно, а иногда и даже вредно. Зависит от спектра помех и резонансных частот конденсаторов. Вот хорошая статья: О развязке питания с примерами с интересными комментариями.
Mr_Destiny
07.04.2016 13:54Простите, я наверно слишком молод и не понимаю классики (никогда не было спектрума), но почему нельзя просто перегнать мелодии в mp3 и слушать с буквально чего угодно? Этому есть какие-то обьективные препятствия кроме «тёплый ламповый звук»?
Пожалуйста, поймите меня правильно — мне действительно интересно зачем нужно городить огород вокруг динамика?dlinyj
07.04.2016 13:58+1Это из разряда почему люди слушают музыку на ламповых усилителях, а не ставят программный звуковой фильтр «лампы» ;)
Mr_Destiny
07.04.2016 14:00+1Я так и подумал. А разве ардуино не разрушает «ламповость» звука? хД
dlinyj
07.04.2016 14:02+1Тут важен оригинальный звуковой чип, который собственно говоря и используется.
ice2heart
07.04.2016 14:06-3А разве lossless формат не дает звук лучшего качества чем может выдать чип?
Или это как лампы подсвеченные светодиодами дающие к окраске звука?dlinyj
07.04.2016 14:16+1Мне кажется вы не понимаете механизм трекерной музыки, раз задаёте такие вопросы.
Если вы хотите потроллить автора поста, то для начала разберитесь в матчасти.ice2heart
07.04.2016 14:27+1Я понимаю как работает трекерная музыка. Я не собираюсь тролить автора. Мне правда интересно есть ли разница между звучанием чипа в «живую» или записанного с него звука в lossless(она конечно будет, но будет ли она заметна). Понятно что трекерный файлик будет во много раз меньше чем lossless, но устройств которые могут его проиграть намного больше.
dlinyj
07.04.2016 14:40Тут мы упираемся в другую проблему — это перегонку звука. Вопрос в том, как сделать её наиболее тёплой и ламповой? А главное целессобразности этой перегонки, если для её осуществления надо делать такую же приблуду. => проще использовать данную приблуду просто из коробки, не морочась с форматами
vvzvlad
08.04.2016 16:05Подключить к выходу этой макетки любой комп с нормальной звуковой картой и писать в lossless. Дальше загнать на любой плеер и наслаждаться. Это, если что, не руководство к действию, а просто альтернатива «спять плеер наполовину, забросить его на два года»
VaalKIA
07.04.2016 15:44>А разве lossless формат не дает звук лучшего качества чем может выдать чип?
Ещё совсем недавно люди, собирая компьютер, выбирали звуковую карту, и в многочисленных обзорах сравнивали всякие MIDI банки и их звучание… как сейчас помню AWE32 и т.п. Типа, если вы хотите насладиться настоящим качеством музыки в вашей любимой игре выбирайте супер мега карту и получите оркестровое качество. С чего бы это, если везде одна и та же цифра (и речь тут не о тёплых ламповых проводах из бумаги)?
Продолжаем тему: формат MOD, вот чем он отличается от Wav, к примеру?
Более современное: Csound http://csound.github.io/documentation.html
Ну а теперь переходим к чиповой музыке и, внезапно, оказывается, что это вовсе не музыка, а программа для чипа и в общем случае, мы можем только логи писать и там где было 100 байт программы, у нас запишутся мегабайты логов. Потом смотрим на параметры чипа, и выясняется ещё и что 44КГц мало, что бы эмулировать по этим логам вывод чипа и один в один всё равно не получится, то есть будет играть огромную роль, качество софта, осуществляющего приближение, то есть речь, о LossLess здесь уже не идёт, но да — можно очень точно воспроизвести этот раздутый лог.Syzd
08.04.2016 07:50Ну сейчас ясное дело цифра, хотя и с разной частотой дискритизации. А тогда если в игре были не mp3, а midi то можно было слышать или пластмассовое детское пианино или сэмплы реального. Хотя и та и та цифровая музыка.
Z80A
07.04.2016 14:30+2Этот вопрос можно задать большинству DIY разработок.
У меня два ответа, серьёзный и не очень, но гораздо ближе к правде:
1. Получить полезный навык и показать другим интересный несложный проект.
2. Мне так захотелось.Mr_Destiny
07.04.2016 14:35+1Да я ж не в претензии — я просто не знал что используется оригинальный звуковой чип (к стати, совсем оригинальный, или «точно такой-же»?), как указал dlinyj
И оффтоп: как мне кажется, мотивация «мне так захотелось» намного более полезная чем все остальное. Разумеется, когда речь идет о чем-то более конструктивном чем тупое лежание на диванеZ80A
07.04.2016 15:10Чип самый что ни на есть оригинальный.
Причём рядом лежит его собрат — YM2149F, который подключается похожим образом, но имеет чуть более другие звуковые оттенки, из-за которых было немало «тёплых ламповых срачей». Вот тоже буду сравнивать.dlinyj
07.04.2016 15:21Вообще, я бы послушал вживую. Не могу сказать, что фанат, но интересно
Z80A
07.04.2016 15:37+1Вот теперь жди пока я в корпусе их оба не соберу.
Тебе же нельзя без корпуса :-)makaroff
07.04.2016 15:43+1Вот у меня тоже уже больше года лежит YM2149F купленный наебэй под ЛПТ-проигрыватель… Готов посмотреть на вашу реализацию ;) Ардуинов и шилдов в запасах ну просто завались!
Z80A
07.04.2016 15:59+1Так что там смотреть — просто подключаете YM вместо AY и вперёд, номера выводов другие, а программирование точно такое же.
Я вот думаю их подключить одновременно параллельно, один в левое, другой в правое ухо — тогда может и усышу разницу.
hockfan
07.04.2016 15:53+2Я, возможно, слепой, но не нашел способа написать вам в личку. Есть такой замечательных архив музыки как zxtunes dot com. Вам должно понравиться.
Z80A
07.04.2016 15:56Спасибо, я знаю про этот сайт. Так как у меня громадный архив трекерной музыки, то там ничего нового я не увидел, но мне очень понравились ремиксы, особенно Putzi — Crazy Comets и Saanvi — Ramparts!
hockfan
07.04.2016 16:01Хорошо. Просто авторы этого сайта стучались ко многим авторам персонально и многое из музыки на этом сайте никогда нигде не публиковалось. А ремиксы я не замечал. Действительно очень круто!
Tabke
08.04.2016 00:17+1Повторил на Yamaha YM2149. Всё работает.
Спасибо автору за интересную статью.
shtirlitsus
Взрывозащищенное исполнение. Отлично!