Mozzi
version v2.0
sound synthesis library for Arduino
SampleHuffman.h
1
/*
2
* SampleHuffman.h
3
*
4
* This file is part of Mozzi.
5
*
6
* Copyright 2013-2024 Tim Barrass and the Mozzi Team
7
*
8
* Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
9
*
10
*/
11
12
#
ifndef
SAMPLEHUFFMAN_H
13
#
define
SAMPLEHUFFMAN_H
14
15
#
include
"mozzi_pgmspace.h"
16
17
/** A sample player for samples encoded with Huffman compression.
18
19
This class and the audio2huff.py script are adapted from "audioout",
20
an Arduino sketch by Thomas Grill, 2011 http//grrrr.org
21
22
Huffman decoding is used on sample differentials,
23
saving 50-70% of space for 8 bit data, depending on the sample rate.
24
25
This implementation just plays back one sample each time next() is called, with no
26
speed or other adjustments.
27
It's slow, so it's likely you will only be able to play one sound at a time.
28
29
Audio data, Huffman decoder table, sample rate and bit depth are defined
30
in a sounddata.h header file. This file can be generated for a sound file with the
31
accompanying Python script audio2huff.py, in Mozzi/extras/python/
32
33
Invoke with:
34
python audio2huff.py --sndfile=arduinosnd.wav --hdrfile=sounddata.h --bits=8 --name=soundtablename
35
36
You can resample and dither your audio file with SOX,
37
e.g. to 8 bits depth @ Mozzi's 16384 Hz sample rate:
38
sox fullglory.wav -b 8 -r 16384 arduinosnd.wav
39
40
Alternatively you can export a sound from Audacity, which seems to have less noticeable or no dithering,
41
using Project Rate 16384 Hz and these output options:
42
Other uncompressed files, Header: WAV(Microsoft), Encoding: Unsigned 8 bit PCM
43
44
The header file contains two lengthy arrays:
45
One is "SOUNDDATA" which must fit into Flash RAM (available in total: 32k for ATMega328)
46
The other is "HUFFMAN" which must also fit into Flash RAM
47
48
*/
49
50
class
SampleHuffman
51
{
52
53
public
:
54
55
/** Constructor
56
@param SOUNDDATA the name of the SOUNDDATA table in the huffman sample .h file
57
@param HUFFMAN_DATA the name of the HUFFMAN table in the huffman sample .h file
58
@param SOUNDDATA_BITS from the huffman sample .h file
59
*/
60
SampleHuffman
(uint8_t
const
* SOUNDDATA, int16_t
const
* HUFFMAN_DATA, uint32_t
const
SOUNDDATA_BITS):
sounddata
(
SOUNDDATA
),
huffman
(
HUFFMAN_DATA
),
sounddata_bits
(
SOUNDDATA_BITS
)
61
{
62
setLoopingOff
(
)
;
63
}
64
65
66
/** Update and return the next audio sample. So far it just plays back one sample at a time without any variable tuning or speed.
67
@return the next audio sample
68
@note timing: about 5 to 40 us, varies continuously depending on data
69
*/
70
inline
71
int16_t
next
()
72
{
73
if
(datapos >= sounddata_bits){
74
if
(looping){
75
// at end of sample, restart from zero, looping the sound
76
datapos = 0;
77
}
else
{
78
return
0;
79
}
80
}
81
82
int16_t dif = decode();
83
current += dif;
// add differential
84
return
current;
85
}
86
87
88
/** Turns looping on, with the whole sample length as the loop range.
89
*/
90
inline
91
void
setLoopingOn
()
92
{
93
looping=
true
;
94
}
95
96
97
/** Turns looping off.
98
*/
99
inline
100
void
setLoopingOff
()
101
{
102
looping=
false
;
103
}
104
105
/** Sets the playhead to the beginning of the sample.
106
*/
107
inline
108
void
start
()
109
{
110
current = 0;
111
datapos = 0;
112
bt = 0;
113
}
114
115
private
:
116
uint8_t
const
* sounddata;
117
int16_t
const
* huffman;
118
uint32_t
const
sounddata_bits;
119
uint32_t datapos;
// current sample position
120
int16_t current;
// current amplitude value
121
bool
looping;
122
uint8_t bt;
123
124
// Get one bit from sound data
125
inline
126
bool
getbit()
127
{
128
const
uint8_t b = datapos&7;
129
//static uint8_t bt;
130
if
(!b) bt = FLASH_OR_RAM_READ<
const
uint8_t>(sounddata+((uint32_t)datapos>>3));
131
// extract the indexed bit
132
return
((uint8_t)bt>>(7-b))&1;
133
}
134
135
136
// Decode bit stream using Huffman codes
137
inline
138
int16_t decode()
139
{
140
int16_t
const
* huffcode = huffman;
141
do
{
142
if
(getbit()) {
143
const
int16_t offs = FLASH_OR_RAM_READ<
const
int16_t>(huffcode);
144
huffcode += offs?offs+1:2;
145
}
146
datapos++;
147
}
148
while
(FLASH_OR_RAM_READ<
const
int16_t>(huffcode++));
149
return
FLASH_OR_RAM_READ<
const
int16_t>(huffcode);
150
}
151
152
153
};
154
155
/**
156
@example 08.Samples/SampleHuffman_Umpah/SampleHuffman_Umpah.ino
157
This example demonstrates the Sample class.
158
*/
159
160
#
endif
// #ifndef SAMPLEHUFFMAN_H
Generated automatically using Doxygen. If info on this page is outdated, incomplete, or wrong, please open an issue at https://github.com/sensorium/Mozzi/issues