Add sample-playing code

This commit is contained in:
Michal Moskal 2017-10-30 18:55:23 +00:00
parent a7795302fc
commit e25590539e
3 changed files with 85 additions and 10 deletions

View File

@ -1,6 +1,6 @@
{
"Sound.buffer": "Returns the underlaying Buffer object.",
"Sound.play": "Play sound with given volume.",
"Sound.play": "Play sound.",
"music": "Generation of music tones.",
"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",

View File

@ -5,17 +5,24 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#define NOTE_PAUSE 20
namespace music {
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);
write(fd, data, size);
int res = write(fd, data, size);
close(fd);
return res;
}
/**
@ -60,6 +67,76 @@ static void _playTone(uint16_t frequency, uint16_t duration, uint8_t volume) {
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.
* @param frequency pitch of the tone to play in Hertz (Hz)
@ -89,14 +166,12 @@ void playTone(int frequency, int ms) {
sleep_ms(1);
}
/** Makes a sound bound to a buffer in WAV format. */
//%
Sound fromWAV(Buffer buf) {
incrRC(buf);
return buf;
}
}
//% fixedInstances
@ -109,10 +184,10 @@ Buffer buffer(Sound snd) {
return snd;
}
/** Play sound with given volume. */
/** Play sound. */
//% promise
void play(Sound snd, int volume) {
// TODO
void play(Sound snd) {
music::playSample(snd);
}
}

View File

@ -38,9 +38,9 @@ declare interface Sound {
//% property shim=SoundMethods::buffer
buffer: Buffer;
/** Play sound with given volume. */
/** Play sound. */
//% promise shim=SoundMethods::play
play(volume: int32): void;
play(): void;
}
// Auto-generated. Do not edit. Really.