summaryrefslogtreecommitdiff
path: root/apps/plugins/tinbox.c
blob: 409ee808c9b335819c0acf5653c02ad66e1bc20c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2014 Franklin Wei
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 */

/* Tonebox is a very-simplifed, MIDI-like format for representing music */
/* The extension for a Tonebox file is .tbx */
/* The format is as follows:
   Header: <f3> <76> -- a tribute to the Z80 :)
   Data:
   - a tone is represented like: <ff> <32-bit big-endian frequency> <32-bit big-endian duration in microseconds>
   - silence is represented as: <00> <32-bit big-endian duration> <32-bit garbage>
*/
#include "plugin.h"
enum plugin_status plugin_start(const void* param)
{
    if(!param)
    {
        rb->splash(HZ, "No .tbx file given!");
        return PLUGIN_ERROR;
    }
    else
    {
        char* filename=(char*)param;
        if(!rb->file_exists(filename))
        {
            rb->splash(HZ, "File does not exist!");
            return PLUGIN_ERROR;
        }
        int fd=rb->open(filename, O_RDONLY);
        unsigned char header[2];
        int ret=rb->read(fd, header, 2);
        if(header[0]!=0xf3 || header[1]!=0x76 || ret!=2)
        {
            rb->splashf(HZ, "Header missing/corrupted!");
            return PLUGIN_ERROR;
        }
        unsigned char buf[9];
        do {
            ret=rb->read(fd, buf, 9);
            if(ret!=9)
                break;
            switch(buf[0])
            {
            case 0xff: /* tone */
            {
                unsigned int freq=(buf[1]<<24)|(buf[2]<<16)|(buf[3]<<8)|buf[4];
                unsigned int dur= (buf[5]<<24)|(buf[6]<<16)|(buf[7]<<8)|buf[8];
                rb->splashf(0, "Playing %u Hz tone for %u microseconds", freq, dur);
                if(freq)
                    rb->piezo_play(dur, freq, true);
                else
#if HZ==100
                    rb->sleep(dur/10000.0); /* FIXME: Assumes that HZ is 100 */
#else
#error "FIXME: HZ assumed to be 100"
#endif
                break;
            }
            case 0:
            {
                unsigned int dur=(buf[1]<<24)|(buf[2]<<16)|(buf[3]<<8)|buf[4];
                rb->splashf(0, "Sleeping %u microseconds", dur);
                rb->sleep(dur/10000.0);
                break;
            }
            default:
                rb->splash(HZ, "Unknown tone/silence byte");
                return PLUGIN_ERROR;
                break;
            }
            rb->yield();
        } while(ret==9);
        rb->close(fd);
    }
    return PLUGIN_OK;
}