Initial commit
This commit is contained in:
commit
cb5b45414b
4 changed files with 290 additions and 0 deletions
71
README.md
Normal file
71
README.md
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
# Téléphone jukebox
|
||||||
|
|
||||||
|
Les instructions qui suivent ont été testées avec des Teensy versions 3.1 et 4.0 (et les modules audio correspondant).
|
||||||
|
|
||||||
|
## Électronique
|
||||||
|
|
||||||
|
* Souder le Teensy sur la carte audio. Le plus compact est de les empiler à l'aide de broches. Faites bien attention à les mettre dans le bon sens (les noms des pins doivent correspondre). Il n'est pas nécessaire de connecter les pins 0 à 5.
|
||||||
|
* Ouvrir le boîtier du téléphone par les deux vis du dessous
|
||||||
|
* Positionner le boulon de réglage glissant sur "3/MINI" (s'il existe sur votre modèle)
|
||||||
|
* Relier le GND du Teensy (un trou libellé "G" ou "GND" sur la carte audio) au fil rouge-blanc du cadran (boulon II)
|
||||||
|
* Relier le fil rouge-blanc du cadran (boulon II) au fil jaune de la prise en T (boulon 15)
|
||||||
|
* Relier le pin 2 du Teensy au fil blanc de la prise en T (boulon 11)
|
||||||
|
* Relier le VGND du module audio (pad de la prise jack le plus vers l'extérieur, dans le coin de la carte) au fil bleu du combiné (boulon 3)
|
||||||
|
* Relier le canal droit ou gauche de la prise jack (un trou libellé L ou R à côté de la prise jack) au fil rouge du combiné (boulon 5)
|
||||||
|
|
||||||
|
Si les fils sont cassants (monobrins), je conseille de les enrouler autour du manchon en métal de la patte qui est fixée au boulon, plutôt que de l'enrouler autour de la vis serrée avec le boulon, afin d'éviter de trop contraindre le fil.
|
||||||
|
|
||||||
|
Attention, GND et VGND ne doivent pas être reliés.
|
||||||
|
|
||||||
|
## Logiciel
|
||||||
|
|
||||||
|
Programmer le Teensy avec le programme fourni.
|
||||||
|
|
||||||
|
## Finition
|
||||||
|
|
||||||
|
* Fabriquer le boîtier d'isolation du Teensy à l'aide d'une imprimante 3D (`teensy_case.stl`), et le placer sur le Teensy (il peut être fixé avec des boulons M3).
|
||||||
|
* Si besoin, faire un petit trou dans la coque du téléphone pour faire passer le câble USB (ce qui permet l'alimentation et la programmation facilement).
|
||||||
|
* Indiquer quelque part sur l'appareil les informations nécessaires à son utilisation ou son amélioration futures (par exemple l'adresse de ce dépôt).
|
||||||
|
|
||||||
|
## Utilisation
|
||||||
|
|
||||||
|
### Fichiers audio
|
||||||
|
|
||||||
|
Les fichiers doivent être au format WAV, taux d'échantillonnage (sampling rate) 44100Hz, 16bit. Les noms des fichiers doivent être de `0.wav` à `9.wav`, ce qui correspond aux chiffres du cadran.
|
||||||
|
|
||||||
|
Le son peut être en stéréo, mais un seul des deux canaux sera joué.
|
||||||
|
|
||||||
|
Pour convertir un fichier audio :
|
||||||
|
* Ouvrir le fichier avec Audacity
|
||||||
|
* Sélectionner la piste en cliquant dessus
|
||||||
|
* Menu "Pistes" -> "Rééchantillonner"
|
||||||
|
* Sélectionner "44100" puis Valider
|
||||||
|
* Menu "Fichier" -> "Exporter" -> "Exporter en WAV"
|
||||||
|
* Choisir l'encodage "Signed 16-bit PCM" et enregistrer le fichier.
|
||||||
|
|
||||||
|
La conversion peut également être effectuée en ligne de commande :
|
||||||
|
```bash
|
||||||
|
ffmpeg -i FICHIER_EXISTANT -y -ar 44100 -ac 1 -aq 16 CHIFFRE.wav
|
||||||
|
```
|
||||||
|
|
||||||
|
### Partitionnement
|
||||||
|
|
||||||
|
Si le Teensy n'arrive pas à lire la carte SD (ce qui est signalé par un bip toutes les 2 secondes), vérifier le partitionnement, qui doit être FAT32 (et non FAT16, par exemple).
|
||||||
|
|
||||||
|
## Améliorations
|
||||||
|
|
||||||
|
Pistes d'amélioration qui n'ont pas encore été réalisées :
|
||||||
|
|
||||||
|
* Les deux sorties L/R pourraient être utilisées pour contrôler deux téléphones. Le Teensy pourrait alors être dans un boîtier externe, relié aux téléphones par leur prise en T (moyennant un recâblage minime à l'intérieur des téléphones).
|
||||||
|
* Faire sonner la cloche ?
|
||||||
|
* Numéros à plusieurs chiffres. Cela nécessite la détection de la fin de la numérotation, soit avec un nombre fixé de chiffres, soit avec un timeout, soit avec des règles de numérotation spéciales, éventuellement avec découverte des fichiers sur la carte SD.
|
||||||
|
* Microcontrôleur moins cher ? (par exemple un ATtiny, mais à voir pour l'audio/SD)
|
||||||
|
* Interaction avec un ordinateur et une carte son (permet plus de complexité et déleste le microcontrôleur de la gestion du son)
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
CopyLeft 2022 Pascal Engélibert
|
||||||
|
|
||||||
|
Ces instructions sont mises à disposition selon les termes de la licence [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||||
|
|
||||||
|
Merci à la compagnie [Léna d'Azy](https://www.lenadazy.fr/) d'avoir financé la conception et la documentation.
|
33
teensy_case.scad
Normal file
33
teensy_case.scad
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2022 Pascal Engélibert
|
||||||
|
// License CC0
|
||||||
|
|
||||||
|
module TeensyCase(
|
||||||
|
bolt_d = 4, // adapted for M3 bolts
|
||||||
|
bolt_d2 = 7.4,
|
||||||
|
bolt_h = 5,
|
||||||
|
l = 39,
|
||||||
|
w = 39,
|
||||||
|
th = 2,
|
||||||
|
bolt1_x = 4.5,
|
||||||
|
bolt1_y = 4,
|
||||||
|
bolt2_x = 33.75,
|
||||||
|
bolt2_y = 4,
|
||||||
|
bolt3_x = 21,
|
||||||
|
bolt3_y = 35,
|
||||||
|
) {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
cube([l, w, th]);
|
||||||
|
translate([bolt1_x, bolt1_y, 0]) cylinder(d=bolt_d2, h=th+bolt_h, $fn=60);
|
||||||
|
translate([bolt2_x, bolt2_y, 0]) cylinder(d=bolt_d2, h=th+bolt_h, $fn=60);
|
||||||
|
translate([bolt3_x, bolt3_y, 0]) cylinder(d=bolt_d2, h=th+bolt_h, $fn=60);
|
||||||
|
}
|
||||||
|
|
||||||
|
translate([bolt1_x, bolt1_y, 0]) cylinder(d=bolt_d, h=th+bolt_h+1, $fn=40);
|
||||||
|
translate([bolt2_x, bolt2_y, 0]) cylinder(d=bolt_d, h=th+bolt_h+1, $fn=40);
|
||||||
|
translate([bolt3_x, bolt3_y, 0]) cylinder(d=bolt_d, h=th+bolt_h+1, $fn=40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TeensyCase(bolt_h=9.2);
|
||||||
|
translate([0, -5, 0]) mirror([0, 1, 0]) TeensyCase(bolt_h=2);
|
BIN
teensy_case.stl
Normal file
BIN
teensy_case.stl
Normal file
Binary file not shown.
186
telephone/telephone.ino
Normal file
186
telephone/telephone.ino
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
* CopyLeft 2022 Pascal Engélibert
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License.
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
||||||
|
You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Telephone Jukebox
|
||||||
|
//
|
||||||
|
// Three types of output may be used, by configuring the code below.
|
||||||
|
//
|
||||||
|
// 1: Digital I2S - Normally used with the audio shield:
|
||||||
|
// http://www.pjrc.com/store/teensy3_audio.html
|
||||||
|
//
|
||||||
|
// 2: Digital S/PDIF - Connect pin 22 to a S/PDIF transmitter
|
||||||
|
// https://www.oshpark.com/shared_projects/KcDBKHta
|
||||||
|
//
|
||||||
|
// 3: Analog DAC - Connect the DAC pin to an amplified speaker
|
||||||
|
// http://www.pjrc.com/teensy/gui/?info=AudioOutputAnalog
|
||||||
|
//
|
||||||
|
// To configure the output type, first uncomment one of the three
|
||||||
|
// output objects. If not using the audio shield, comment out
|
||||||
|
// the sgtl5000_1 lines in setup(), so it does not wait forever
|
||||||
|
// trying to configure the SGTL5000 codec chip.
|
||||||
|
//
|
||||||
|
// The SD card may connect to different pins, depending on the
|
||||||
|
// hardware you are using. Uncomment or configure the SD card
|
||||||
|
// pins to match your hardware.
|
||||||
|
//
|
||||||
|
// Two pins can be used (one for hang up detection and one for counting), but it also works well with only one pin for both functions.
|
||||||
|
|
||||||
|
#include <Audio.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
|
#include <SerialFlash.h>
|
||||||
|
|
||||||
|
//#define PIN_PULSE 4
|
||||||
|
#define PIN_STOP 2
|
||||||
|
|
||||||
|
#define PULSE_DELAY 100
|
||||||
|
|
||||||
|
unsigned long pulses_end = 0;
|
||||||
|
unsigned int pulses = 0;
|
||||||
|
bool pulse = false;
|
||||||
|
|
||||||
|
AudioMixer4 mix2;
|
||||||
|
AudioMixer4 mix1;
|
||||||
|
AudioSynthWaveform waveform1;
|
||||||
|
AudioPlaySdWav wav1;
|
||||||
|
// Use one of these 3 output types: Digital I2S, Digital S/PDIF, or Analog DAC
|
||||||
|
AudioOutputI2S phone1;
|
||||||
|
//AudioOutputSPDIF phone1;
|
||||||
|
//AudioOutputAnalog phone1;
|
||||||
|
//On Teensy LC, use this for the Teensy Audio Shield:
|
||||||
|
//AudioOutputI2Sslave phone1;
|
||||||
|
|
||||||
|
AudioConnection c1(waveform1, 0, mix1, 0);
|
||||||
|
AudioConnection c2(waveform1, 0, mix2, 0);
|
||||||
|
AudioConnection c3(wav1, 0, mix1, 1);
|
||||||
|
AudioConnection c4(wav1, 1, mix2, 1);
|
||||||
|
AudioConnection c5(mix1, 0, phone1, 0);
|
||||||
|
AudioConnection c6(mix2, 0, phone1, 1);
|
||||||
|
|
||||||
|
AudioControlSGTL5000 sgtl5000_1;
|
||||||
|
|
||||||
|
// Use these with the Teensy Audio Shield
|
||||||
|
#define SDCARD_CS_PIN 10
|
||||||
|
#define SDCARD_MOSI_PIN 7
|
||||||
|
#define SDCARD_SCK_PIN 14
|
||||||
|
|
||||||
|
// Use these with the Teensy 3.5 & 3.6 SD card
|
||||||
|
//#define SDCARD_CS_PIN BUILTIN_SDCARD
|
||||||
|
//#define SDCARD_MOSI_PIN 11 // not actually used
|
||||||
|
//#define SDCARD_SCK_PIN 13 // not actually used
|
||||||
|
|
||||||
|
// Use these for the SD+Wiz820 or other adaptors
|
||||||
|
//#define SDCARD_CS_PIN 4
|
||||||
|
//#define SDCARD_MOSI_PIN 11
|
||||||
|
//#define SDCARD_SCK_PIN 13
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
pinMode(PIN_STOP, INPUT_PULLUP);
|
||||||
|
//pinMode(PIN_PULSE, INPUT_PULLUP);
|
||||||
|
|
||||||
|
AudioMemory(8);
|
||||||
|
|
||||||
|
// Comment these out if not using the audio adaptor board.
|
||||||
|
// This may wait forever if the SDA & SCL pins lack
|
||||||
|
// pullup resistors
|
||||||
|
sgtl5000_1.enable();
|
||||||
|
sgtl5000_1.volume(0.5);
|
||||||
|
|
||||||
|
waveform1.begin(WAVEFORM_SINE);
|
||||||
|
waveform1.frequency(440);
|
||||||
|
|
||||||
|
SPI.setMOSI(SDCARD_MOSI_PIN);
|
||||||
|
SPI.setSCK(SDCARD_SCK_PIN);
|
||||||
|
if(!SD.begin(SDCARD_CS_PIN)) {
|
||||||
|
// Error: Cannot read SD card
|
||||||
|
while(true) {
|
||||||
|
if(!digitalRead(PIN_STOP)) {
|
||||||
|
waveform1.amplitude(0.5);
|
||||||
|
delay(250);
|
||||||
|
waveform1.amplitude(0.0);
|
||||||
|
delay(1750);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void play_track(unsigned int track) {
|
||||||
|
char filename[16];
|
||||||
|
sprintf(filename, "%d.WAV", track);
|
||||||
|
wav1.play(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
/*if(digitalRead(PIN_STOP)) {
|
||||||
|
waveform1.amplitude(0.0);
|
||||||
|
if(wav1.isPlaying()) {
|
||||||
|
wav1.stop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(wav1.isPlaying()) {
|
||||||
|
waveform1.amplitude(0.0);
|
||||||
|
} else {
|
||||||
|
waveform1.amplitude(0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(digitalRead(PIN_PULSE)) {
|
||||||
|
if(!pulse) {
|
||||||
|
pulses ++;
|
||||||
|
pulse = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(pulse) {
|
||||||
|
pulse = false;
|
||||||
|
pulses_end = millis() + PULSE_DELAY;
|
||||||
|
}
|
||||||
|
else if(pulses) {
|
||||||
|
if(millis() >= pulses_end) {
|
||||||
|
if(!digitalRead(PIN_STOP))
|
||||||
|
play_track(pulses);
|
||||||
|
pulses = 0;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// If phone is hang up
|
||||||
|
if(digitalRead(PIN_STOP)) {
|
||||||
|
// Stop tone and music
|
||||||
|
waveform1.amplitude(0.0);
|
||||||
|
if(wav1.isPlaying()) {
|
||||||
|
wav1.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!pulse) {
|
||||||
|
pulse = true;
|
||||||
|
pulses ++;
|
||||||
|
pulses_end = millis() + PULSE_DELAY;
|
||||||
|
}
|
||||||
|
else if(millis() > pulses_end) {
|
||||||
|
pulses = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(wav1.isPlaying()) {
|
||||||
|
// Stop tone
|
||||||
|
waveform1.amplitude(0.0);
|
||||||
|
} else {
|
||||||
|
// Start tone
|
||||||
|
waveform1.amplitude(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pulse) {
|
||||||
|
pulse = false;
|
||||||
|
pulses_end = millis() + PULSE_DELAY;
|
||||||
|
} else if(pulses && millis() > pulses_end) {
|
||||||
|
play_track(pulses % 10);
|
||||||
|
pulses = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
}
|
Loading…
Reference in a new issue