Add sample-playing code
This commit is contained in:
parent
a7795302fc
commit
e25590539e
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"Sound.buffer": "Returns the underlaying Buffer object.",
|
"Sound.buffer": "Returns the underlaying Buffer object.",
|
||||||
"Sound.play": "Play sound with given volume.",
|
"Sound.play": "Play sound.",
|
||||||
"music": "Generation of music tones.",
|
"music": "Generation of music tones.",
|
||||||
"music.beat": "Return the duration of a beat in milliseconds (the beat fraction).",
|
"music.beat": "Return the duration of a beat in milliseconds (the beat fraction).",
|
||||||
"music.beat|param|fraction": "the fraction of the current whole note, eg: BeatFraction.Half",
|
"music.beat|param|fraction": "the fraction of the current whole note, eg: BeatFraction.Half",
|
||||||
|
@ -5,17 +5,24 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
|
||||||
#define NOTE_PAUSE 20
|
#define NOTE_PAUSE 20
|
||||||
|
|
||||||
namespace music {
|
namespace music {
|
||||||
|
|
||||||
uint8_t currVolume = 2;
|
uint8_t currVolume = 2;
|
||||||
|
uint8_t *lmsSoundMMap;
|
||||||
|
|
||||||
void writeDev(void *data, int size) {
|
int writeDev(void *data, int size) {
|
||||||
|
DMESG("write dev %d", size);
|
||||||
int fd = open("/dev/lms_sound", O_WRONLY);
|
int fd = open("/dev/lms_sound", O_WRONLY);
|
||||||
write(fd, data, size);
|
int res = write(fd, data, size);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,6 +67,76 @@ static void _playTone(uint16_t frequency, uint16_t duration, uint8_t volume) {
|
|||||||
writeDev(&cmd, sizeof(cmd));
|
writeDev(&cmd, sizeof(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool pumpMusicThreadRunning;
|
||||||
|
static pthread_mutex_t pumpMutex;
|
||||||
|
static Buffer currentSample;
|
||||||
|
static int samplePtr;
|
||||||
|
static pthread_cond_t sampleDone;
|
||||||
|
|
||||||
|
static void pumpMusic() {
|
||||||
|
if (currentSample == NULL) {
|
||||||
|
if (samplePtr > 0 && *lmsSoundMMap == 0) {
|
||||||
|
samplePtr = 0;
|
||||||
|
DMESG("END");
|
||||||
|
pthread_cond_broadcast(&sampleDone);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t buf[250]; // max size supported by hardware
|
||||||
|
buf[0] = SOUND_CMD_SERVICE;
|
||||||
|
int len = min((int)sizeof(buf) - 1, currentSample->length - samplePtr);
|
||||||
|
if (len == 0) {
|
||||||
|
DMESG("EOF");
|
||||||
|
decrRC(currentSample);
|
||||||
|
currentSample = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf + 1, currentSample->data + samplePtr, len);
|
||||||
|
int rc = writeDev(buf, len + 1);
|
||||||
|
if (rc > 0) {
|
||||||
|
samplePtr += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *pumpMusicThread(void *dummy) {
|
||||||
|
while (true) {
|
||||||
|
sleep_core_us(10000);
|
||||||
|
pthread_mutex_lock(&pumpMutex);
|
||||||
|
pumpMusic();
|
||||||
|
pthread_mutex_unlock(&pumpMutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void playSample(Buffer buf) {
|
||||||
|
if (lmsSoundMMap == NULL) {
|
||||||
|
int fd = open("/dev/lms_sound", O_RDWR);
|
||||||
|
lmsSoundMMap = (uint8_t*) mmap(NULL, 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
DMESG("sound map: %p", lmsSoundMMap);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pumpMusicThreadRunning) {
|
||||||
|
pumpMusicThreadRunning = true;
|
||||||
|
pthread_t pid;
|
||||||
|
pthread_create(&pid, NULL, pumpMusicThread, NULL);
|
||||||
|
pthread_detach(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&pumpMutex);
|
||||||
|
*lmsSoundMMap = 1; // BUSY
|
||||||
|
uint8_t cmd[] = {SOUND_CMD_PLAY, (uint8_t)((currVolume / 33) + 1)};
|
||||||
|
writeDev(cmd, 2);
|
||||||
|
decrRC(currentSample);
|
||||||
|
currentSample = buf;
|
||||||
|
incrRC(buf);
|
||||||
|
samplePtr = 44; // WAV header is 44 bytes
|
||||||
|
pumpMusic();
|
||||||
|
pthread_cond_wait(&sampleDone, &pumpMutex);
|
||||||
|
pthread_mutex_unlock(&pumpMutex);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play a tone through the speaker for some amount of time.
|
* Play a tone through the speaker for some amount of time.
|
||||||
* @param frequency pitch of the tone to play in Hertz (Hz)
|
* @param frequency pitch of the tone to play in Hertz (Hz)
|
||||||
@ -89,14 +166,12 @@ void playTone(int frequency, int ms) {
|
|||||||
sleep_ms(1);
|
sleep_ms(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Makes a sound bound to a buffer in WAV format. */
|
/** Makes a sound bound to a buffer in WAV format. */
|
||||||
//%
|
//%
|
||||||
Sound fromWAV(Buffer buf) {
|
Sound fromWAV(Buffer buf) {
|
||||||
incrRC(buf);
|
incrRC(buf);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//% fixedInstances
|
//% fixedInstances
|
||||||
@ -109,10 +184,10 @@ Buffer buffer(Sound snd) {
|
|||||||
return snd;
|
return snd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Play sound with given volume. */
|
/** Play sound. */
|
||||||
//% promise
|
//% promise
|
||||||
void play(Sound snd, int volume) {
|
void play(Sound snd) {
|
||||||
// TODO
|
music::playSample(snd);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
4
libs/music/shims.d.ts
vendored
4
libs/music/shims.d.ts
vendored
@ -38,9 +38,9 @@ declare interface Sound {
|
|||||||
//% property shim=SoundMethods::buffer
|
//% property shim=SoundMethods::buffer
|
||||||
buffer: Buffer;
|
buffer: Buffer;
|
||||||
|
|
||||||
/** Play sound with given volume. */
|
/** Play sound. */
|
||||||
//% promise shim=SoundMethods::play
|
//% promise shim=SoundMethods::play
|
||||||
play(volume: int32): void;
|
play(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-generated. Do not edit. Really.
|
// Auto-generated. Do not edit. Really.
|
||||||
|
Loading…
Reference in New Issue
Block a user