Menu
JAQForum Ver 19.10.27

Forum Index : Microcontroller and PC projects : read out carolling christmas bells

   Page 4 of 5    
Posted: 02:23am
13 Nov 2025
Copy link to clipboard
twofingers
Guru


Hi Frank,
You're not making this easy for us.

The WAV format is unusual (type 17) and the signal level is abysmal.



I made a first attempt with Cooledit, but only found 8 different tones:

D3, D#3, A6, E6, F#6, A7, D7, G7



That doesn't seem very plausible to me.

My suggestion: You could use a better microphone and ring the bells individually. Or check if they might even be stamped? ;-)
The storage format shouldn't be ADPCM, but PCM, mono, 16 bits/sample.

Kind regards
Michael
 
Posted: 02:42am
13 Nov 2025
Copy link to clipboard
TassyJim
Guru


My version of CoolEdit using waterfall display



Frequencies detected (first number is time from start):
0 3500 3200 2130 1500 1210 1060


0.81 2750
1.04 2400
1.3 2130
1.53 2020
1.75 1900
1.99 1800
2.21 1600
2.46 1500
2.69 3500 1400
2.925 1350
3.165 3500 1210
3.41 3200 2130 1060


Code used to convert to notes
'

FUNCTION fToNote(toneX AS FLOAT) AS STRING
   LOCAL FLOAT diff, stdtone, stddiff
LOCAL INTEGER noteNum, octave
 LOCAL allnotes$ = "G#A A#B C C#D D#E F F#G G#A ",  noteX$

   noteNum = 12*LOG(toneX/440)/LOG(2)+49              ' piano key closest to tone
   stdtone = 2^((noteNum-49)/12) * 440           ' actual tone of the piano key
   stddiff = 2^((noteNum-48)/12) * 440 - stdtone ' frequency difference betweem adjacent keys
   diff = (toneX - stdtone)/stddiff*100               ' error of tone in percent to next note
   IF noteNum > 87     THEN : octave = 8
   ELSEIF noteNum > 75 THEN : octave = 7
   ELSEIF noteNum > 63 THEN : octave = 6
   ELSEIF noteNum > 51 THEN : octave = 5
   ELSEIF noteNum > 39 THEN : octave = 4
   ELSEIF noteNum > 27 THEN : octave = 3
   ELSEIF noteNum > 15 THEN : octave = 2
   ELSEIF noteNum > 3 THEN : octave = 1
   ELSE                : octave = 0
   ENDIF
   IF noteNum > 0 THEN
     noteX$ = MID$(allnotes$,(noteNum MOD 12) * 2 +1,2)
     fToNote = STR$(toneX,8,1)+" Hz  "+noteX$+STR$(octave)+STR$(diff,4,0)+"%"
   ELSE
     fToNote =  STR$(toneX,8,1)+" Hz         "
   ENDIF

 END FUNCTION
 
 PRINT fToNote(3500)
 PRINT fToNote(3200)
 PRINT fToNote(2750)
 PRINT fToNote(2400)
 PRINT fToNote(2130)
 PRINT fToNote(2020)
 PRINT fToNote(1900)
 PRINT fToNote(1800)
 PRINT fToNote(1600)
 PRINT fToNote(1500)
 PRINT fToNote(1400)
 PRINT fToNote(1350)
 PRINT fToNote(1200)
 PRINT fToNote(1060)

 DO
INPUT "frequency";fr
PRINT fToNote(fr)
LOOP


Results:
   3500.0 Hz  A 7 -10%
   3200.0 Hz  G 7  34%
   2750.0 Hz  F 7 -26%
   2400.0 Hz  D 7  36%
   2130.0 Hz  C 7  30%
   2020.0 Hz  B 6  38%
   1900.0 Hz  A#6  32%
   1800.0 Hz  A 6  38%
   1600.0 Hz  G 6  34%
   1500.0 Hz  F#6  23%
   1400.0 Hz  F 6   4%
   1350.0 Hz  E 6  40%
   1200.0 Hz  D 6  36%
   1060.0 Hz  C 6  22%


Jim
 
Posted: 05:57am
13 Nov 2025
Copy link to clipboard
phil99
Guru


  Quote  and the signal level is abysmal
The first program I tried was unable to extract anything useful from it.
Audacity gave some results but I don't think they are useful as when I zoom in there are too few digital steps to reliably see the frequencies properly.

Is this meant to be the track that starts with 4 chimes at once followed by each of the 12 bells from highest to lowest?

That is the one that is needed but at a much higher volume.

Anyway this is what came out, but may not be correct. There are 14 so 2 are either harmonics or 2 bells have an extra resonant mode unrelated to the main one.
3487
2680
2375
2140
2016
1899
1803
1607
1487
1403
1349
1240
1080
.
Edited 2025-11-13 16:18 by phil99

Footnote added 2025-11-13 16:24 by phil99
I missed one. the first 3 are 3487, 3187, 2680
 
Posted: 06:14am
13 Nov 2025
Copy link to clipboard
TassyJim
Guru


I agree that the signal level was way too low.
I started by amplifying it by 20dB but there is still the background noise to contend with.

Most of the tones I detected were in the 30-40% high but it is promising to see so many agreeing with each other.

There are also two phantom tones in my list.

Jim
 
Posted: 07:49am
13 Nov 2025
Copy link to clipboard
Frank N. Furter
Guru

Please excuse the poor sound quality!

I will try again tomorrow with a different recorder.

Frank
 
Posted: 10:25am
13 Nov 2025
Copy link to clipboard
Volhout
Guru

Frank,

In case you have a picomite VGA, you can analyze the audio yourself.
Connect the audio signal to GP26(*) on the picomite VGA, and run below (very elementary) spectrum analyzer.

 'GP26 audio spectrum analyzer VGA
 
 'ping-pong ADC and calculate RMS value and fft
 'runs on picomite VGA in mode 1 (640x480 monochrome)
 framebuffer create
 framebuffer write f
 
 'system parameters
 Option base 1
 n=512                   'samples
 Dim a(n),b(n)           'ping pong buffers
 Dim c(n),d(n)           'processing buffer
 
 'hardware parameters
 offset = -1.66          'hardware default
 freq = 10000             'ADC sampling frequency
 
 'test signal generated from PWM
 'SetPin gp0,pwm
 'PWM 0,50,50            '50Hz, 50% d.c.
 
 'test signal from audio output
 play tone 2000,1000
 
 'open the ADC and start first conversion
 'SetPin gp26,ain
 ADC OPEN freq,1,INT_RDY
 ready=0:pingpong=1
 ADC START a()
 
 'main routine
 Do
   'every n/freq a new buffer is filled with samples and ready flag raised
   'we have time to process the data. Using math commands we gain time
   'rms is 4ms/512 samples, fft = 44ms/512 samples, plotting the graph consumes most time
   text 0,0,str$(timer,3,0)
   timer=0
   
   If ready Then
     If pingpong Then
       MATH ADD b(),offset,c()
     Else
       MATH ADD a(),offset,c()
     EndIf
     
     rms = Math(SD c())                 'math(sd a()) does all the math to
     'calculate rms from an array
     
     text 480,0,"RMS = "+str$(rms*scale,1,4)
     ready=0
   
     'fft calculate magnitude
     MATH FFT MAGNITUDE c(),d()
     dummy=math(max d(),p%) 'determin what cell in the array has the highest value
     inc p%,-1              'because option bas 1
     if p%>n/2 then p%=n-p% 'copy frequency mirror bin
     text 200,0,"Peak freq = "+str$(p%*freq/n,5,0)+" Hz"
     
     scale=(MM.VRES-10)/n
     MATH SCALE d(),scale,d()        'scale to match samples on 470 vertical
     'resolution
     'fft spectrum show
     bars=n/2-1:wdth=Int(MM.HRES/bars)
     For i=2 To bars'n/2 - 1
       BOX i*wdth,470-d(i),wdth,d(i)
     Next i
   EndIf
   
   framebuffer copy f,n
   CLS
   
 Loop While Inkey$=""
 Save compressed image "fft_bars.bmp"
End
 
 'interrupt routine
Sub INT_RDY
 If pingpong Then
   ADC START b()
 Else
   ADC START a()
 EndIf
 pingpong=1-pingpong
 ready=1
End Sub


The screen will show the spectrum, the top right corner will show the level you input, try to increase the volume so get close to 1Vrms. Not higher, since you overdrive the input ADC. The sampler works at 10kHz, so you should be able to detect all frequencies up to 5kHz.



This is the input circuit I used.




Volhout

P.S. the audio analyzer loop time is 70ms, so it most likely is fast enough to detect all notes (200ms between bells).
P.P.S. for the purists: the display routine and FFT are much slower than the ADC sample engine, so there is more data acquired than is shown (roughly 40% more).
Edited 2025-11-13 21:04 by Volhout
 
Posted: 11:37am
13 Nov 2025
Copy link to clipboard
Frank N. Furter
Guru

  That's very cool!!! I'll try that this weekend.
That will also help me a lot in making the sound bodies.

Frank
 
Posted: 12:45pm
13 Nov 2025
Copy link to clipboard
twofingers
Guru


Hi Frank,
First off: I like Harm's program. I had planned something similar, but not by directly reading the voltage values, rather by reading them from a WAV file.

I had assumed your bells were magnetically activated. However, I've seen fake bells online with an additional speaker. In that case, we obviously don't necessarily need a WAV file. Could you clarify that with a description and also explain what you're aiming for, what exactly you're planning?
Kind regards
Michael
 
Posted: 01:28pm
13 Nov 2025
Copy link to clipboard
Frank N. Furter
Guru

Michael,

on the one hand, I'm afraid that the µC will die at some point and then my glockenspiel would become useless. On the other hand, I would like to recreate it with mechanical bells or sound elements. That means probably with sound tubes like in the link from Volhout on the first page of this thread.
Controlling the bells correctly would already work now – so the first point no longer worries me...

Yes, the bells on my glockenspiel are struck by electromagnets.

  twofingers said  I've seen fake bells online with an additional speaker.
I would just use an MP3 player then – that would be ugly.

I want to build it in exactly the same way as my original, using electromechanical components. Playback via the Picomite sound output is only used to avoid errors.

Frank

P.S.:
  twofingers said  I had planned something similar, but not by directly reading the voltage values, rather by reading them from a WAV file.

That would definitely be very useful!
Edited 2025-11-13 23:33 by Frank N. Furter
 
Posted: 01:51pm
13 Nov 2025
Copy link to clipboard
twofingers
Guru


Hi Frank,
all right!
Then I don't understand how you plan to use Harm's program. Your microcomputer only gives you on/off values.
Please don't misunderstand, this isn't a criticism of Harm's program! I imagine it would be useful if it used an amplified microphone signal as input.
 
Posted: 01:58pm
13 Nov 2025
Copy link to clipboard
Frank N. Furter
Guru

Michael,

First of all, it's about finding the right bell frequencies (unless you're faster at it ) and then creating sound elements. To do this, I will have to measure the individual sound elements and, if necessary, adjust their length until the desired tone is achieved.

Frank
 
Posted: 02:28pm
13 Nov 2025
Copy link to clipboard
Volhout
Guru

Update to the spectrum analyzer for pico VGA.



GP26_audio_analyzer_VGA_2.zip

Volhout
 
Posted: 03:00pm
13 Nov 2025
Copy link to clipboard
twofingers
Guru


  Frank N. Furter said  Michael,

First of all, it's about finding the right bell frequencies (unless you're faster at it ) ...
Frank
As I said, this is how I would proceed: Number the bells. Connect a microphone to the PC, start a recording program (in my case it would be Cooledit 2000), and ring each bell individually with a fixed object (a mallet) corresponding to the numbered bell – with short pauses in between. Check if the signal level is high enough. Then save everything as an MP3 file. Compress it as a ZIP archive and upload it here.


@Harm, looks really good! Thanks!
 
Posted: 03:17pm
13 Nov 2025
Copy link to clipboard
Mixtel90
Guru


Are you trying to imitate the bells or get the notes correct? It's quite possible that the bells aren't tuned to any particular scale, just done by someone's ear. Their notes may be produced with digital accuracy, but only relative to each other as the master oscillator could be a temperature-dependent RC network. It wouldn't matter in real life as they are unlikely to be played along with other instruments.

If you want to get the notes correct then find a common tune that they play, then find the musical score for that tune. It will tell you the notes precisely. You can then use Volhout's table to get the exact frequencies that you need to produce for each note. The common Christmas tunes can be found all over the place.

Another way. Use a Pico PLAY TONE to produce a C note. Then compare it with the bells to find one that sounds closest. Volhout's table will then give you the frequencies of the surrounding bells as they will be a 12-note scale. C may or may not be in the middle.

.
Edited 2025-11-14 01:20 by Mixtel90
 
Posted: 03:53pm
13 Nov 2025
Copy link to clipboard
Volhout
Guru

Hi mick,

Your suggestion was Franks plan B.
My VGA spectrum analyzer is plan F. Soo many plans.

Volhout
 
Posted: 06:51pm
13 Nov 2025
Copy link to clipboard
Mixtel90
Guru


Good job I didn't read everything then. :)
 
Posted: 09:08pm
13 Nov 2025
Copy link to clipboard
phil99
Guru


So far the main issue in getting the frequencies is getting a noise free recording with enough amplitude. Several of us have used PC based analyzers but the current recordings are difficult to read. The Pico based analyzers will have the same issue.

How were the bells arranged for the recording? If they are resting on anything the tone and loudness may be affected.
I think suspending them in a tight circle around the microphone might give better results.

Audacity for example can read the frequencies required for constructing a mechanical playback but also the "envelope" of each bell for the synthesized playback option.
But as Frank said, that would be little different to a MP3 player.
 
Posted: 06:42am
14 Nov 2025
Copy link to clipboard
TassyJim
Guru


To summarize the results from Phil's and my tests.
We found 14 separate notes. Two more than the number of bells.
With a less noisy recording, we could probably eliminate the phantom notes.

The majority of the tones are half way between standard notes.

Piano tone   standard note
key   found
85          3520.0 Hz  A 7
     3487
84          3322.4 Hz  G#7
     3200
83          3136.0 Hz  G 7
82          2960.0 Hz  F#7
81          2793.8 Hz  F 7
     2680
80          2637.0 Hz  E 7
79          2489.0 Hz  D#7
     2375
78          2349.3 Hz  D 7
77          2217.5 Hz  C#7
     2140
76          2093.0 Hz  C 7
     2016
75          1975.5 Hz  B 6
     1899
74          1864.7 Hz  A#6
     1803
73          1760.0 Hz  A 6
72          1661.2 Hz  G#6
     1607
71          1568.0 Hz  G 6
     1487
70          1480.0 Hz  F#6
     1403
69          1396.9 Hz  F 6
     1349
68          1318.5 Hz  E 6
67          1244.5 Hz  D#6
     1240
66          1174.7 Hz  D 6
65          1108.7 Hz  C#6
     1080
64          1046.5 Hz  C 6


First column is the piano key number
second column is the tones found in the recording
finally the standard notes as a reference.

The interval between notes was a consistent (considering electro-mechanical parts) 240mS or multiple of.

I don't have a musical bone in my body so there may be errors in the descriptions

Jim
 
Posted: 09:17am
14 Nov 2025
Copy link to clipboard
Mixtel90
Guru


The bells, being bells, may not be tuned to a normal key. They are probably close to the correct musical relationship to each other, but not tuned. The precise frequencies don't matter as they won't be played with other instruments.
Get the sequences right first.

here's an example:


D        G      G    A    G-F#       E - E
We     wish    you   a    Merry    Christmas,

E         A      A    B    A-G       F# - D
We      wish    you   a   Merry     Christmas,

D       B      B    ^C     B-A        G  -  E     D    D    E - A     F#       G
We    wish    you    a    Merry      Christmas    and   a   Happy      New Year!



D           G - G     G     F#    F#    G    F#   E      D
Good      tidings     we   bring  to   you   and your   kin;

A            B - A     G     ^D - ^D      E    E    E - A     F#       G
Good        tidings   for   Christmas    and   a    Happy       New Year!


The relationship between notes will always be the same. This example is in the key of G major, but the bells may be in anything. The "We" at the beginning will be the biggest (lowest note) bell. Count up from there to get the others:
1 D
2 D#
3 E
4 F
5 F#
6 G
7 G#
8 A
9 A#
10 B
11 C
12 ^D

You often find that the last note of a song is the base note for the key that it is in, so G in this case as it's in G major.

As I said, although these are shown as G major it may not be in concert pitch so you don't actually know the precise frequencies. However, if you start at D on a piano or similar the notes will be in the correct relationship, even if they don't correspond to what the bells sound like! This is perfectly playable on a xylophone, for example. It's just a case of getting the timing right. You can get that from the musical stave, which shows the relationship between the note lengths.
 
Posted: 12:45am
15 Nov 2025
Copy link to clipboard
phil99
Guru


As noted previously some solenoid pulses are longer than others. They appear in most, if not all tunes in the full recording. It could be that these are deliberate to get a louder chime.

So I suggest an experiment to find out. Disconnect a bell solenoid from the player and hook it up to a Pico via a transistor (with 2.2kΩ base resistor and reverse biased diode from collector to +12V) to +12V and run a command line program to compare the loudness of the standard pulse duration with the longer one.
Do :Pulse GP0, 35 :Pause 200 :Pulse GP0, 55 :Pause 200 :Loop

' "Xylophone player pulse filter.bas"
Dim integer Bell.note, Note.prev
Dim float Bell.time, Bell.prev, Ding, interval '15 'Add to, or subtract from pulse duration (mS)

For n=0 To 11
 SetPin MM.Info(pinno "GP"+Str$(n)),DOUT
Next

'*******Add your recorded file name here.*************
'Open "RecordBellsFrank.dat" For Input As #1
'Open "BellSample.dat" For Input As #1
Open "RemappedALL.dat" For Input As #1
Print
Print "List of solenoid pulses that are greater than 40mS"
Print
Print "Pulse mS","Solenoid(s)",,"recorded time S"
Print

Do
 Input #1, Bell.time, Bell.note 'get the data
 If Bell.note Then Note.prev=Bell.note
 Ding=bell.time-Bell.prev
 If (Bell.note=0) And (Ding > 40) Then  Print Ding, Note.prev, Bin$(Note.prev,12), Bell.time/1000
 Bell.prev = Bell.time
Loop Until Eof(#1)
Print
End
Output
List of solenoid pulses that are greater than 40mS

Pulse mS     Solenoid(s)         recorded time S

134.7   3264   110011000000     0.260116
55.467  128    000010000000     2.628993
56.5    1024   010000000000     44.339032
53.961  64     000001000000     199.690203
60.181  1024   010000000000     234.761601
53.417  4      000000000100     265.160832
54.228  2048   100000000000     471.215816
54.272  2304   100100000000     687.591088
57.378  32     000000100000     732.344462
55.947  576    001001000000     774.17021
53.774  72     000001001000     809.217
54.222  1024   010000000000     837.960805
57.378  1024   010000000000     897.256997
55.912  2048   100000000000     933.399468
52.333  288    000100100000     973.86001
54.386  16     000000010000     1053.768813
54.298  288    000100100000     1086.714309
55.975  512    001000000000     1153.06176
56.077  160    000010100000     1184.831196
56.034  576    001001000000     1215.966319
54.52   2112   100001000000     1277.618936
54.563  256    000100000000     1308.651649
52.435  64     000001000000     1340.188582
56.166  72     000001001000     1401.284143
54.394  32     000000100000     1438.408004
54.563  8      000000001000     1487.414759
54.545  512    001000000000     1517.914275
54.46   64     000001000000     1611.356135
55.727  1280   010100000000     1669.557919
525.765         2564   101000000100     1698.23718

When you build your new version you will be using different solenoids so may need to experiment with pulse durations to get the same effect.

The Xylophone player program can then be adapted to replace the original pulse times with your new times.

Edit.
Another version of the player to show the individual tracks and which pulses are longer than normal. To speed it up the 2 lines that do the actual playing in real time have been commented out.
It uses the file "RemappedALL.dat".
The time intervals shown are from the start of one pulse to the start of the next.
eg for track 0 (bell test) the pulses are 35mS separated by 200mS so the interval is 235mS.
' "Xylophone player & analyser.bas"
Dim integer n, Bell.note, track 'number of on/off transitions in the sequence
Dim float Bell.time, Bell.prev, Pulse.change = -0 'Add to, or subtract from pulse duration (mS)
Dim LP$ 'indicate pulses greater than 40mS
For n=0 To 11
  SetPin MM.Info(pinno "GP"+Str$(n)),DOUT
Next

'*******Add your recorded file name here.*************
Open "RemappedALL.dat" For Input As #1
Print
Print " Track 0 - Bell Test"
Print "Input time",,"Solenoid(s)",, "interval", "Pulse length"
Timer = 0

Do
  Input #1, Bell.time, Bell.note 'get the data
  If Bell.note Then  Inc Bell.time, -Pulse.change 'adjust pulse duration
'    Do While Timer < Bell.time : Loop 'wait for next note or pulse
'  Port(gp0,12) = Bell.note 'start / end solenoid pulse

  If Bell.time-Bell.prev > 3000 Then
    Inc track
    Print :Print
    Print " Track";track,"===================================================="
    Print "Input time",,"Solenoid(s)",, "interval", "Pulse length"
    Print
  EndIf

  If Bell.note Then      Print Bell.time,, Bin$(Bell.note,12),, Bell.time-Bell.prev,

  If Bell.note=0 And Bell.time-Bell.prev > 40 Then
    LP$ =  "Long Pulse" 'indicate pulses greater than 40mS
   Else
    LP$ = ""
  EndIf

  If Bell.note=0 Then Print Bell.time-Bell.prev, LP$

  If Bell.note Then  Bell.prev = Bell.time
  If Bell.note=0 Then  Ding.prev = Bell.time

Loop Until Eof(#1)
Port(gp0,12) = 0

End

The minimum interval in each track (tempo I guess).
Track  Tempo mS Tempo beats/S (approx.)
0      235      4.2  Bell test track
1      157      6.4
2      273      4.5
3      234      4.3
4      204      4.9
5      204      4.9
6      204      4.9
7      233      4.3
8      234      4.3
9      204      4.9
10     233      4.3
11     233      4.3
12     204      4.9
13     298      3.4
14     204      4.9
15     233      4.3
16     233      4.3
17     233      4.3
18     204      4.9
19     233      4.3
20     272      3.4
21     204      4.9
22     234      4.3
23     234      4.3 - another bell test track
24     156      6.4

Edited 2025-11-15 21:27 by phil99
 
   Page 4 of 5    
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025