hello there!
im currently try to build my lightsaber but in the guide it says you need a sd card but the Teensy 3.2 has no slot for one and the prop shield too. so im a bloody beginner with this all and my question may be stupid but I found no answer to this. I tought the code is playing and storing the sounds in the teensy or the prop shield?
and I forgot one thing I use a WS2812B Led strip is this supported? and where do I need to make changes in case it is supported
You can store your sound font on the prop shield flash, but there isnât a lot of space there, so itâs very limited. Also, nobody has done that in a while, so itâs possible that it wonât work âout of the boxâ, but if so I can help with fixing that.
Itâs possible to use an external SD card reader, like I did:
https://fredrik.hubbe.net/lightsaber/electronics.html
Itâs also possible to use a Teensy 3.5 which has an SD card reader on it.
And yes, WS2812B strips are absolutely supported.
thanks for the fast reply!
ok good so I will try to get it work. I donât need much sound files but how do I change them when not using a sd card? has the prop shield be connected while uploading the code to the teensy?
and im not finding a link to the style generator
ah ok good so I just have too change the led name to WS2812B?
and thanks for your help!
If you select MTP in Arduino->Tools->USB type, then ProffieOS will add an mtp server that lets you upload/download files to the flash memory on the prop shield. The prop shield doesnât have to be connected to upload code, but obviously the code wonât work well if it expects a prop shield that isnât there. You donât need to change the LED name. (Where would you even do that?)
ah ok so I need to change that and re upload the code.
good so this was stupid I thought I need to change this in WS2812B
BladeConfig blades[] = {
{ 0, WS2811BladePtr<144, WS2811_ACTUALLY_800kHz | WS2811_GRB>(), CONFIGARRAY(presets) },
};
also where do I change the sounds that will be used like humming turn off and on swings etc.?
Thatâs the font that you would upload to the prop shield flash through MTP.
that would be this file I guess right?
#ifndef MTP_MTP_STORAGE_SD_H
#define MTP_MTP_STORAGE_SD_H
// Storage implementation for SD. SD needs to be already initialized.
class MTPStorage_SD : public MTPStorageInterface {
public:
explicit MTPStorage_SD(MTPD* mtpd) { mtpd->AddStorage(this); }
private:
File index_;
uint8_t mode_ = 0;
uint32_t open_file_ = 0xFFFFFFFEUL;
File f_;
uint32_t index_entries_ = 0;
struct Record {
uint32_t parent;
uint32_t child; // size stored here for files
uint32_t sibling;
uint8_t isdir;
uint8_t scanned;
char name[14];
};
bool readonly() override { return false; }
bool has_directories() override { return true; }
uint64_t size() override { return 1 << 30; }
uint64_t free() override { return 1 << 29; }
uint32_t free_objects() override { return 0xFFFFFFFEUL; }
const char* GetName() override {
return âSD Cardâ;
}
void OpenIndex() {
if (index_) return;
mtp_lock_storage(true);
index_ = SD.open(âmtpindex.datâ, FILE_WRITE);
mtp_lock_storage(false);
}
void WriteIndexRecord(uint32_t i, const Record& r) {
OpenIndex();
mtp_lock_storage(true);
index_.seek(sizeof(r) * i);
index_.write((char*)&r, sizeof(r));
mtp_lock_storage(false);
}
uint32_t AppendIndexRecord(const Record& r) {
uint32_t new_record = index_entries_++;
WriteIndexRecord(new_record, r);
return new_record;
}
// TODO(hubbe): Cache a few records for speed.
Record ReadIndexRecord(uint32_t i) {
Record ret;
if (i > index_entries_) {
memset(&ret, 0, sizeof(ret));
return ret;
}
OpenIndex();
mtp_lock_storage(true);
index_.seek(sizeof(ret) * i);
index_.read(&ret, sizeof(ret));
mtp_lock_storage(false);
return ret;
}
void ConstructFilename(int i, char* out) {
if (i == 0) {
strcpy(out, â/â);
} else {
Record tmp = ReadIndexRecord(i);
ConstructFilename(tmp.parent, out);
if (out[strlen(out)-1] != â/â)
strcat(out, â/â);
strcat(out, tmp.name);
}
}
void OpenFileByIndex(uint32_t i, uint8_t mode = O_RDONLY) {
if (open_file_ == i && mode_ == mode)
return;
char filename[256];
ConstructFilename(i, filename);
mtp_lock_storage(true);
f_.close();
f_ = SD.open(filename, mode);
open_file_ = i;
mode_ = mode;
mtp_lock_storage(false);
}
// MTP object handles should not change or be re-used during a session.
// This would be easy if we could just have a list of all files in memory.
// Since our RAM is limited, weâll keep the index in a file instead.
bool index_generated = false;
void GenerateIndex() {
if (index_generated) return;
index_generated = true;
mtp_lock_storage(true);
SD.remove("mtpindex.dat");
mtp_lock_storage(false);
index_entries_ = 0;
Record r;
r.parent = 0;
r.sibling = 0;
r.child = 0;
r.isdir = true;
r.scanned = false;
strcpy(r.name, "/");
AppendIndexRecord(r);
}
void ScanDir(uint32_t i) {
Record record = ReadIndexRecord(i);
if (record.isdir && !record.scanned) {
OpenFileByIndex(i);
if (!f_) return;
int sibling = 0;
while (true) {
mtp_lock_storage(true);
File child = f_.openNextFile();
mtp_lock_storage(false);
if (!child) break;
Record r;
r.parent = i;
r.sibling = sibling;
r.isdir = child.isDirectory();
r.child = r.isdir ? 0 : child.size();
r.scanned = false;
strcpy(r.name, child.name());
sibling = AppendIndexRecord(r);
child.close();
}
record.scanned = true;
record.child = sibling;
WriteIndexRecord(i, record);
}
}
bool all_scanned_ = false;
void ScanAll() {
if (all_scanned_) return;
all_scanned_ = true;
GenerateIndex();
for (uint32_t i = 0; i < index_entries_; i++) {
ScanDir(i);
}
}
uint32_t next_;
bool follow_sibling_;
void StartGetObjectHandles(uint32_t parent) override {
GenerateIndex();
if (parent) {
if (parent == 0xFFFFFFFF) parent = 0;
ScanDir(parent);
follow_sibling_ = true;
// Root folder?
next_ = ReadIndexRecord(parent).child;
} else {
ScanAll();
follow_sibling_ = false;
next_ = 1;
}
}
uint32_t GetNextObjectHandle() override {
while (true) {
if (next_ == 0)
return 0;
int ret = next_;
Record r = ReadIndexRecord(ret);
if (follow_sibling_) {
next_ = r.sibling;
} else {
next_++;
if (next_ >= index_entries_)
next_ = 0;
}
if (r.name[0]) return ret;
}
}
void GetObjectInfo(uint32_t handle,
char* name,
uint32_t* size,
uint32_t* parent) override {
Record r = ReadIndexRecord(handle);
strcpy(name, r.name);
*parent = r.parent;
*size = r.isdir ? 0xFFFFFFFFUL : r.child;
}
uint32_t GetSize(uint32_t handle) {
return ReadIndexRecord(handle).child;
}
void read(uint32_t handle,
uint32_t pos,
char* out,
uint32_t bytes) override {
OpenFileByIndex(handle);
mtp_lock_storage(true);
f_.seek(pos);
f_.read(out, bytes);
mtp_lock_storage(false);
}
bool DeleteObject(uint32_t object) override {
char filename[256];
Record r;
while (true) {
r = ReadIndexRecord(object == 0xFFFFFFFFUL ? 0 : object);
if (!r.isdir) break;
if (!r.child) break;
if (!DeleteObject(r.child))
return false;
}
// We can't actually delete the root folder,
// but if we deleted everything else, return true.
if (object == 0xFFFFFFFFUL) return true;
ConstructFilename(object, filename);
bool success;
mtp_lock_storage(true);
if (r.isdir) {
success = SD.rmdir(filename);
} else {
success = SD.remove(filename);
}
mtp_lock_storage(false);
if (!success) return false;
r.name[0] = 0;
int p = r.parent;
WriteIndexRecord(object, r);
Record tmp = ReadIndexRecord(p);
if (tmp.child == object) {
tmp.child = r.sibling;
WriteIndexRecord(p, tmp);
} else {
int c = tmp.child;
while (c) {
tmp = ReadIndexRecord(c);
if (tmp.sibling == object) {
tmp.sibling = r.sibling;
WriteIndexRecord(c, tmp);
break;
} else {
c = tmp.sibling;
}
}
}
return true;
}
uint32_t Create(uint32_t parent,
bool folder,
const char* filename) override {
uint32_t ret;
if (parent == 0xFFFFFFFFUL) parent = 0;
Record p = ReadIndexRecord(parent);
Record r;
if (strlen(filename) > 12) return 0;
strcpy(r.name, filename);
r.parent = parent;
r.child = 0;
r.sibling = p.child;
r.isdir = folder;
// New folder is empty, scanned = true.
r.scanned = 1;
ret = p.child = AppendIndexRecord(r);
WriteIndexRecord(parent, p);
if (folder) {
char filename[256];
ConstructFilename(ret, filename);
mtp_lock_storage(true);
SD.mkdir(filename);
mtp_lock_storage(false);
} else {
OpenFileByIndex(ret, FILE_WRITE);
}
return ret;
}
void write(const char* data, uint32_t bytes) override {
mtp_lock_storage(true);
f_.write(data, bytes);
mtp_lock_storage(false);
}
void close() override {
mtp_lock_storage(true);
uint32_t size = f_.size();
f_.close();
mtp_lock_storage(false);
Record r = ReadIndexRecord(open_file_);
r.child = size;
WriteIndexRecord(open_file_, r);
open_file_ = 0xFFFFFFFEUL;
}
};
#endif
No, that file is for using MTP with SD cards.
This is the file that implement support for MTP on serialflash:
Note that the serialflash doesnât actually support directories, so you probably can only have one font. Not that it matters, since you will probably not have room for more than one font anyways.
You donât really need to know which file implements what though. All you should need to worry about is what defines to put (and not put) in your config file. For instance, you should NOT have this in your config file:
#define ENABLE_SD
Instead, you should have:
#define ENABLE_SERIALFLASH
If you have ENABLE_SERIALFLASH
and select MTP in arduino->tools->usb type, the ProffieOS should automatically use the file I linked above to make the serialflash storage available through MTP. Note that if youâre on a mac, you might need some android tools installed to get MTP support.
ok good then I will change this to enable serialfalsh! and the Arduino I already changed to mtp storage so I got no notification that there was a problem.
so I need to select the fond I want and put it in the serial flash code?
thank you for the help Im a total beginner in this code stuff
Youâll need to upload the font files to the serialflash. Since there are no directories, all the files will just be in the top level directory. In the config file, youâll make a preset that uses ââ for the font path.
If everything work, proffieos will find the files and play them from there.
ok could you show me how it should look or can look? does it know wich sound to play?
Yes, it knows which sounds to play.
This page explains most about how the file structure works for fonts:
Sound Font Configuration ¡ profezzorn/ProffieOS Wiki ¡ GitHub
On a serialflash, there wouldnât be a directory though, just files.
Most fonts you can find/buy/download already have the files named correctly, so you would just upload them to the serialflash and call it a day. (Assuming they fit, which they probably wonâtâŚ)
ok i will try it but canât I just use the sound files from the teensy saber site?
Yes you can, but you will need to pick one font, and even then you probably will need to remove some of the files to make it fit.
good I will do that!
but I can use only the sounds from one or can I copy one from another and mix it?
You can mix sounds from different fonts.
I would recommend making it work before you start doing that.
good you helped me out a lot thanks again. I will try all this and if im running in a problem I will post here again!