Having been looking closely at many aspects of audio within the app_rpt code, particularly with regards to ensuring more consistent levels (and no clipping/distortion) for all users, I am noticing some interesting things in the app_rpt code. I thought I would start documenting some things here as I investigate further.
The first thing that should be noted is that pretty much all nodes I’m aware of use C-Media CM1xx ICs. This of course refers to real nodes - not phone or PC apps such as DVSM or iaxRpt. But in the class of real nodes, whether they be repeaters, Pi-hat (SA818) nodes, mobile radio nodes, or radio-less nodes, probably 99% of anything built in the past 10 years is using either a C-Media CM119A, CM108AH, CM108B or CM119B.
The CM1xx A/AH versions replaced the original (no suffix) CM108/119 ICs over 10 years ago, and those then went EOL according to C-Media several years ago to be replaced with the B suffix versions, which have significantly different specs, which no one I know of has yet fully characterized and confirmed through testing. (The A ICs are still available though, which is another story.)
The App_rpt code however essentially treats everything as a (15-year old) CM108/119, with a few twists. The original 108 and 119 were essentially identical, the only major difference (as far as ASL is concerned) being that the 119 has 4 more GPIOs.
The A versions made some minor changes but from what I can tell the specs did not significantly change. The ADC on all 6 variants has an input range of 2.88Vpp. The DAC output ranges vary considerably however, as shown below:
The changes in the B versions were much more significant. The crystal was removed, presumably with the internal PLL extracting 12MHz clock from the USB bus, but I was not able to confirm that with C-Media. The LF response is reduced by about 6dB < 100Hz. The ADC SNR and THD was significantly improved. And the gain settings are quite different:
ADC:
Orig: 0 - 22.5 dB range in 16 steps, with +20dB boost option
A/AH: 0 - 23.9 dB range in 16 steps, with +22.5dB boost option
B: -12 - 23 dB range in 36 steps, with 12 or 22 dB boost option
Which with boost off should translate to:
Orig: 0 - 22.5 dB range in 16 steps
A/AH: 0 - 23.9 dB range in 16 steps
B: 0 - 35 dB range in 36 steps
DAC:
Orig, A/AH: -45 - 0 dB range in 38 steps
B: -37 - 0 dB range in 38 steps
There are discrepancies on A&B datasheets between the gain ranges and steps shown on the block diagram vs. the specs tables. So the only way to confirm the above would be to test on an A & B version and confirm what actual voltages come out of the DAC for a full-scale input at various gain step settings, and similarly what happens with a known voltage on the ADC input with different gain settings.
Based on testing I’ve been doing on some ANR100 radio-less nodes, one with a CM108AH and the other with a CM108B, I notice the B needs significantly higher level settings. I use rxmix of 100 and txmix of 500 on the AH, but need rxmix of 750 and txmix of 800 on the B. (Both with rxboost=off). That’s a huge difference, particularly between 100 to 750 for rxmixset. I’m running about 1.4Vpp into ADC which should only need 6dB of boost to be at the ADC rated input range of 2.88Vpp. The specs above would imply the B has more gain in both directions than the A’s, but my measurements seem to show the opposite. The 108B DAC is rated at 941mVrms out vs. 1.25Vrms for the AH at 10KΩ but that’s only a 2.5dB difference.
A big question is are the B’s suitable for use in nodes and URIs. Their reduced ADC response below 100Hz could be an issue for apps using usbradio to CTCSS decode of lower PL tones, but that doesn’t apply to most small personal nodes or radio-less nodes. There has been speculation that the B’s might not have as good of clock/sample timing stability or temperature range but I’ve seen no confirmation of that. The lower gain of the B’s could be an issue in some apps but most apps don’t need a ton of gain and support for lower gains can be better in some cases. Lastly the B’s are widely available, in current production, and have 10dB better ADC noise specs.
The next variable is ASL itself, which has defines for all these variants, but really doesn’t do much differently between them, and has some clear inconsistencies. It looks like some efforts were made to put in some scaling for CM119B vs. A but the values are the same (1000) and thus no scaling is actually done (see C119B_ADJUSTMENT).
Then there is this bit of code in chan_simpleusb.c where it outputs audio to the USB interface:
/* Adjust the audio level for CM119 A/B devices */
if (o->devtype != C108_PRODUCT_ID) {
register int v;
sp = (short *) o->simpleusb_write_buf;
for (i = 0; i < FRAME_SIZE; i++) {
v = *sp;
v += v >> 3; /* add *.125 giving * 1.125 */
v -= *sp >> 5; /* subtract *.03125 giving * 1.09375 */
if (v > 32765.0) {
v = 32765.0;
} else if (v < -32765.0) {
v = -32765.0;
}
*sp++ = v;
}
}
And this in chan_usbradio.c where it reads USB audio:
/* Decrease the audio level for CM119 A/B devices */
if (o->devtype != C108_PRODUCT_ID) {
register short *sp = (short *) (o->usbradio_read_buf + o->readpos);
register float v;
register int i;
for (i = 0; i < res / 2; i++) {
v = ((float) *sp) * 0.800;
*sp++ = (int) v;
}
}
And this where it writes USB audio:
/* For the CM108 adjust the audio level */
if (o->devtype != C108_PRODUCT_ID) {
register short *sp = (short *) o->usbradio_write_buf;
register float v;
register int i;
for (i = 0; i < sizeof(o->usbradio_write_buf) / 2; i++) {
v = ((float) *sp) * 1.10;
if (v > 32765.0) {
v = 32765.0;
} else if (v < -32765.0) {
v = -32765.0;
}
*sp++ = (int) v;
}
}
This above 3 code excerpts are all conditioned on != C108_PRODUCT_ID, which will always be true on any node made in at least the past 10 years. This appears to be a major issue that could result in perfectly good incoming IAX audio being digitally clipped before being output to the DAC. Usbradio is scaling all Tx audio going to the DAC by 110%, while at the same time attenuating all incoming audio by 20%, increasing the likelihood of digital clipping on Tx audio, wasting 20% of available dynamic range on incoming audio, and eating up CPU cycles to do floating point scaling on every sample, apparently as a hack to match levels to an IC that has been out of production for over 10 years. Simpleusb does pretty much the same thing but scaling in a more CPU efficient way to 109.375% on Tx audio but then not doing any scaling of Rx audio.
Update: Did some testing today with both simpleusb and usbradio drivers and confirmed these code sections above are completely unnecessary and should be removed asap. At that point there may be some significant work to properly characterize these various ICs and see if there might be a good way to get their gains to be more consistent by adjusting the mixer settings rather then by scaling the incoming and outgoing audio streams. Ideally the rx and tx mix settings could be in dBV instead of arbitrary (unitless) numbers, and ASL would then figure the exact mixer settings required to achieve those actual input and levels on each CM1xxx variant.