Рандомное воспроизведение файлов DFplayer

Gridzilla
Offline
Зарегистрирован: 25.10.2019

Привет всем. Продолжаю рзбираться в премудростях дальше. Чуть вопроса такая: есть топик по наливатору http://arduino.ru/forum/proekty/nalivator-avtomatizirovannaya-mashina-kotoraya-budet-razlivat-alkogol-po-stopkam Это как бы вводная.. Есть такая штука как воспроизведение тостов. Вместо кучи кейсов, как вот тут, допустим, http://arduino.ru/forum/proekty/nalivator-avtomatizirovannaya-mashina-kotoraya-budet-razlivat-alkogol-po-stopkam?page=8#comment-481135 сделал так, чтобы не быть привязанным к количеству файлов на карте памяти.

#include "DFRobotDFPlayerMini.h"
int8_t files_tost = 0; // Не более 100 тостов. Да и куда их больше?

// Тосты
void Tost() {
  randomSeed(analogRead(7));
      lcd.clear();
      lcd.setCursor(0, 1);
      lcd.print(F("   БЕРИ РЮМКУ   "));
      delay (2000);
      myDFPlayer.volume(vol_tost);
      delay (100);
      myDFPlayer.playFolder (2, random (files_tost)); 
}

void setup()  {
files_tost = myDFPlayer.readFileCountsInFolder(2); // Считаем сколько треков в папке с тостами 02
}

void loop() {
Tost();
}

Все работает, воспроизводит и т.д., но... Суть вопроса в том, то рандом хиленький, то есть имеют место быть повторения. При чем могут следовать друг за другом. Подтолкните в нужную сторону, чтобы избежать этого. Бибоиотека для плеера эта https://github.com/DFRobot/DFRobotDFPlayerMini

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

а я в той теме писал, как сделать неповторяющийся random. Гдетта на 8 странице. 

нет, вру, на 10-й

http://arduino.ru/forum/proekty/nalivator-avtomatizirovannaya-mashina-kotoraya-budet-razlivat-alkogol-po-stopkam?page=9#comment-481230

Gridzilla
Offline
Зарегистрирован: 25.10.2019

DetSimen пишет:

а я в той теме писал, как сделать неповторяющийся random. Гдетта на 8 странице. 

нет, вру, на 10-й

http://arduino.ru/forum/proekty/nalivator-avtomatizirovannaya-mashina-kotoraya-budet-razlivat-alkogol-po-stopkam?page=9#comment-481230

Да, спасибо, читал конечно это. Как ниже написал Алексей, много незнакомых букв для меня, без комментариев тяжело.. И как в этом случае расположить файлы на карте памяти, чтобы не быть жестко привязанным к их количеству? Вместо 

"Tost 1",
03     "Tost 2",
04     "Tost 3",
05     "Tost 4",

написать ссылки на файлы на карте?

Дело-то еще в том, что все мп3 раскиданы по трем папкам 01, 02 и 03. В первой служебные, второй тосты, а третьей музыка для плеера. Поэтому и ищу что-то по проще, что было бы более понятно :)) 

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ну, первым делом, я бы все тосты в 1 папку закинул. это прям напрашивается. 

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

короче, к вечеру грядки закончу формировать, да переделаю, пока трезвый, чтоб не тосты а индекс отдавал, если тебе не под силу.  

Gridzilla
Offline
Зарегистрирован: 25.10.2019

DetSimen пишет:

Ну, первым делом, я бы все тосты в 1 папку закинул. это прям напрашивается. 

Они у меня и так все в одной отдельной папке сидят. Остальное по своим. 

И да, буду признателен если подмогЁте. 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Gridzilla пишет:
рандом хиленький

особенно если его неправильно использовать. Кто ж пишет randomSeed(analogRead(7)); при каждом вызове? Это надо один раз делать в начале.

Gridzilla пишет:
имеют место быть повторения. При чем могут следовать друг за другом.

Это абсолютно нормально. Более того, математически доказанный факт, что в идеальной бесконечной последовательности случайных объектов, обязательно встретится любая наперед заданная конечная подпоследовательность. Например, миллион нулей подряд - обязательно встретится.

Поэтому, если Вам нужна неповторяющаяся последовательность, то Вам нужен не random, а нечто другое.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

сам проверяй, у мня на даче свободных Дуинов нету, все трудятся не смыкая глаз. 

class TSongs {  // класс песенки
protected:
	uint8_t Count;
	uint8_t *SongsIdx;
	uint8_t Size;

	void Clear(void) {
		Count = Size;
		for (uint8_t i = 0; i < Size; i++)  SongsIdx[i] = i;
	}

	void HideSong(const uint8_t ATostNum) {
		for (int8_t i = ATostNum; i < Count - 1; i++) SongsIdx[i] = SongsIdx[i + 1];
		Count--;
	}

	TSongs() {}; // пустой каструктор не разрешен

public:

	// ASongCount скока песенок надо воспроизвести
	//
	TSongs(const uint8_t ASongsCount) {   
		SongsIdx = new uint8_t[Size = ASongsCount];
		Clear();
	};

	~TSongs() {
		delete[] SongsIdx;
	}

	// отдает случайный индекс следующей песенки
	// 
	uint8_t getNext() {
		if (Count == 0) Clear();
		uint8_t idx = random(Count);
		uint8_t result = SongsIdx[idx];
		HideSong(idx);
		return result;
	}

};

обьявляешь переменную

TSongs Songs(количество песенок); // не более 255

и вызываешь потом там, где надо получить индекс след. песенки

uint8_t next  = Songs.getNext();

DFPlayer.play(next);

в пределах количества песенок не повторится ни одна.  Потом произвоцтвенный цыкал пойдет сначала. 

raven78
Offline
Зарегистрирован: 03.11.2019

@DetSimen

Спасибо за подсказку. Тоже озадачивался таким рандомом, но я тупо объявлял массив с  количеством тостов, потом перемешивал в нём всё,  что несколько  увеличивало динамическую память в зависимости от количества тостов, например 255 тостов это 255 байт, как то жалко хранить номер тоста в одном байте))) . Тут как я понял динамическое выделение памяти и потом последующее её очищение, занятость динамической памяти не зависит от количества треков.

В Строка 13  опечатка, вроде не правильный тип переменной букву u забыли поставить, а то треки только до 127 выдаёт. Короче с Вашего позволения беру на вооружение)))

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Рандом рандомный (по настоящему) может возникнуть только из аналога. Берем нечто шумящее ( типа диода шотки) и считываем из него периодически "0" или "1"

 

raven78
Offline
Зарегистрирован: 03.11.2019

Аналоговый пин не подключенный никуда, сам по себе нечто шумящее)). Всеми тут ненавистный Гайвер делает так

unsigned long seed = 0;
for (int i = 0; i < 16; i++) {
  seed *= 4;
  seed += analogRead(A0) & 3;
}
randomSeed(seed);

Не плохо получается

Gridzilla
Offline
Зарегистрирован: 25.10.2019

ЕвгенийП пишет:

Gridzilla пишет:
рандом хиленький

особенно если его неправильно использовать. Кто ж пишет randomSeed(analogRead(7)); при каждом вызове? Это надо один раз делать в начале.

Теперь знаю. Спасибо!

ЕвгенийП пишет:

Это абсолютно нормально. Более того, математически доказанный факт, что в идеальной бесконечной последовательности случайных объектов, обязательно встретится любая наперед заданная конечная подпоследовательность. Например, миллион нулей подряд - обязательно встретится.

Поэтому, если Вам нужна неповторяющаяся последовательность, то Вам нужен не random, а нечто другое.

Таки да, в любой последовательности будут повторения. Это нам вдолбили еще во времена универа на вышке. Но вот как-то сократить эти повторения можно же? Буду учиться...

DetSimen пишет:

сам проверяй, у мня на даче свободных Дуинов нету, все трудятся не смыкая глаз. 

Эх, молчит плеер :(( Вставил в скетч перед сетапом, далее как написано объявил TSongs Songs(files_tost); так как количество считывается в сетапе. Даже если прописать там цифрами нужное количество, не хочет он играть. Хреново когда много не понимаешь... Да.. 

 

Если uint8_t next  = Songs.getNext(); оставить в лупе, то молчит. 

Если вынести после объявления

TSongs Songs(files_tost); // не более 255

uint8_t next  = Songs.getNext();
то воспроизводит постоянно один и тот же файл из первой папки. А у меня их три на карте памяти :((
mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

raven78 пишет:

Аналоговый пин не подключенный никуда, сам по себе нечто шумящее))

Там надо ловить не 0 -1, а между какими - то значениями. Хотя тоже рандом, но кислый ИМХО

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

В строке 13 да, читать uint8_t

А по работоспособности, только завтра в город паехаю, возьму еще несколько дуин, с плеером, проверю 

Gridzilla
Offline
Зарегистрирован: 25.10.2019

Оно работает если в лупе, когда необходимо воспроизвести файл вставить все три строки

TSongs Songs(files_tost); // не более 255
uint8_t next  = Songs.getNext();
myDFPlayer.playFolder(2, next);

В таком случае да, воспроизводит как и положено из нужной папки. Но вот правильно ли это? Может тогда эти три строки обернуть в процедуру и вставлять уже ее? Чисто для эстетики и уменьшения количества строк. 

Gridzilla
Offline
Зарегистрирован: 25.10.2019

Проверил поболее. В одном режиме воспроизводит после налива как надо, а в других может зависнуть на одной мелодии... 

sadman41
Offline
Зарегистрирован: 19.10.2016

TSongs Songs(files_tost); объяви глобалом, а getNext() вызывай в лупе.

Gridzilla
Offline
Зарегистрирован: 25.10.2019

sadman41 пишет:

TSongs Songs(files_tost); объяви глобалом, а getNext() вызывай в лупе.

Так вообще глючно работает. Может раза два-три не воспроизвести вообще, а может зависнуть на одной мелодии. Что гораздо чаще, чем если вызывать каждый раз когда нужен тост. Если все три строчки в одном месте, то глючит меньше, но повторяется и может так же не воспроизвести что-то. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Я понял. Мой код тебе не поможет, забудь

sadman41
Offline
Зарегистрирован: 19.10.2016

DetSimen пишет:

Я понял. Мой код тебе не поможет, забудь

Вопрос у меня есть... Имеется ли в талмудах решение проблемы проверки валидности enum переменной при непоследовательных значениях членов enum-а?

Т.е. девайс мне шлёт коды возврата (байт), которые я преобразую к enum (ну, чтобы умным казаться). Однако коды эти непоследовательны: enum { code1 = 0x23, code2 = 0x41, code3 = 43 } codes_t. И вот я принял от девайса байт 0x35. Как бы мне без адова свича проверить, что 0x35 ошибочен или наоборот - валиден? 

 

Gridzilla
Offline
Зарегистрирован: 25.10.2019

DetSimen пишет:

Я понял. Мой код тебе не поможет, забудь


Ок. Жаль :(( но и на том спасибо! Буду изучать дальше толмуты...