mirror of
https://github.com/radio95-rnt/fm95.git
synced 2026-02-26 11:22:00 +01:00
change the config file stuff
This commit is contained in:
208
fm95.md
208
fm95.md
@@ -1,126 +1,106 @@
|
||||
# FM95 Configuration File
|
||||
# FM95 config file
|
||||
|
||||
This document describes the configuration file format for the FM95 FM transmitter software.
|
||||
|
||||
## File Format
|
||||
|
||||
The configuration file uses standard INI format with sections and key-value pairs. Comments can be added using the `#` or `;` character at the beginning of a line.
|
||||
|
||||
## Configuration Sections
|
||||
|
||||
### [fm95] - Main Settings
|
||||
|
||||
This section contains the core FM95 transmission parameters.
|
||||
|
||||
#### Audio Processing
|
||||
|
||||
- **`stereo`** (0 or 1, default: 0)
|
||||
Enable stereo transmission. Set to 1 for stereo, 0 for mono. Or set to 2 for Polar Stereo
|
||||
|
||||
- **`audio_volume`** (float)
|
||||
Audio input volume multiplier. 1.0 = unity gain, values > 1.0 may cause distortion.
|
||||
|
||||
- **`master_volume`** (float)
|
||||
Master output volume control. Affects overall transmission level.
|
||||
|
||||
- **`clipper_threshold`** (float)
|
||||
Audio clipper threshold to prevent overmodulation. Lower values = more aggressive clipping.
|
||||
|
||||
- **`preemphasis`** (float, microseconds)
|
||||
Pre-emphasis time constant in microseconds. Common values: 50 (Europe), 75 (North America).
|
||||
|
||||
#### RDS (Radio Data System)
|
||||
|
||||
- **`rds_streams`** (integer, range: 1-4)
|
||||
Number of RDS data streams to process simultaneously. More streams allow richer RDS data but require more processing power.
|
||||
|
||||
#### MPX (Multiplex) Settings
|
||||
|
||||
- **`mpx_power`** (float)
|
||||
MPX signal power level. For BS412.
|
||||
|
||||
- **`mpx_deviation`** (float, Hz)
|
||||
Maximum frequency deviation for MPX signals. Standard value is 75000 Hz for FM broadcast.
|
||||
|
||||
#### Calibration
|
||||
|
||||
- **`calibration`** (0-2, default: 0)
|
||||
Enable calibration mode for testing and adjustment. (2 enables 40 hz square wave instead of the 400 hz sine)
|
||||
|
||||
#### Frequency Deviation
|
||||
|
||||
- **`deviation`** (float, Hz)
|
||||
Maximum frequency deviation. Standard FM broadcast uses 75000 Hz. This setting affects the master_volume automatically.
|
||||
|
||||
### [devices] - Audio Device Configuration
|
||||
|
||||
This section specifies the audio devices to use for input and output.
|
||||
|
||||
- **`input`** (string, max 63 chars)
|
||||
Primary audio input device
|
||||
|
||||
- **`output`** (string, max 63 chars)
|
||||
MPX input
|
||||
|
||||
- **`mpx`** (string, max 63 chars)
|
||||
MPX (multiplex) input device for subcarrier input
|
||||
|
||||
- **`rds`** (string, max 63 chars)
|
||||
RDS signal input
|
||||
|
||||
## Example Configuration
|
||||
By default the config file path is on /etc/fm95.conf, it's a ini formatted config consisting of this syntax:
|
||||
|
||||
```ini
|
||||
# FM95 Configuration File
|
||||
# Lines starting with # are comments
|
||||
|
||||
[fm95]
|
||||
# Enable stereo transmission
|
||||
stereo=1
|
||||
|
||||
# Audio levels (1.0 = unity gain)
|
||||
audio_volume=0.8
|
||||
master_volume=1.0
|
||||
|
||||
# Prevent overmodulation
|
||||
clipper_threshold=0.9
|
||||
|
||||
# Pre-emphasis for Europe (50µs) or North America (75µs)
|
||||
preemphasis=50
|
||||
|
||||
# Enhanced stereo processing
|
||||
polar_stereo=1
|
||||
|
||||
# RDS configuration
|
||||
rds_streams=2
|
||||
|
||||
# MPX settings
|
||||
mpx_power=0.1
|
||||
mpx_deviation=75000
|
||||
|
||||
# Standard FM deviation
|
||||
deviation=75000
|
||||
|
||||
# Enable calibration mode for testing
|
||||
calibration=0
|
||||
|
||||
[section]
|
||||
key=value
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
## Audio Pipeline
|
||||
|
||||
1. **RDS Streams**: Maximum of 4 RDS streams are supported. Exceeding this limit will cause an error.
|
||||
`Pulse` -> `Audio Preamp` -> `AGC` -> `LPF` -> `Pre-Emphasis` -> `Audio Volume` -> `Audio Clipper` -> `Stereo Encoder` -> `BS412` -> `Master Volume` -> `Output Clipper`
|
||||
|
||||
2. **String Length**: Device names are limited to 63 characters maximum.
|
||||
Below are the sections and their keys
|
||||
|
||||
3. **Deviation Interaction**: The `deviation` setting automatically adjusts `master_volume` using the formula: `master_volume *= (deviation / 75000.0)`. Set deviation last if you want to override master_volume.
|
||||
## fm95
|
||||
|
||||
4. **Audio Levels**: Keep audio levels reasonable to prevent distortion. Start with conservative values and adjust as needed.
|
||||
### stereo
|
||||
|
||||
5. **Preemphasis**: Use 50µs for European broadcast standards, 75µs for North American standards.
|
||||
Simple boolean, set to 0, or 1
|
||||
|
||||
## Troubleshooting
|
||||
### rds_streams
|
||||
|
||||
- **No audio**: Check device names with system audio tools
|
||||
- **Distorted audio**: Reduce audio_volume and clipper_threshold
|
||||
- **Poor stereo separation**: Enable polar_stereo and adjust mpx_power
|
||||
- **RDS not working**: Verify rds device and ensure rds_streams ≤ 4
|
||||
Integer from 0 to 4, it sets how many channels to capture from RDS95, note that both values have to match, otherwise god may have mercy on your RDS decoders
|
||||
|
||||
### clipper_threshold
|
||||
|
||||
Sets the peak to peak value of the Audio Clipper, defaults to one, but can be disabled by setting 0
|
||||
|
||||
### preemphasis
|
||||
|
||||
Sets the Preemphasis tau, basically how much highs is boosted, by default and in Europe it is 50µs, but in the USA and South Korea, use 75µs. Expects unit in microseconds
|
||||
|
||||
### calibration
|
||||
|
||||
Simple integer, set to 1 to output a sine wave at 400 Hz, which should correspond to 75 KHz deviation by default. Set to 2 for a 60 Hz square wave, this test is to set the tilt, more on which later
|
||||
|
||||
### master_volume
|
||||
|
||||
Float value to set the master volume, 1 by default, set to 0 to mute MPX
|
||||
|
||||
### audio_volume
|
||||
|
||||
Float value to set the audio volume, also 1 by default, set to 0 to mute audio itself, but stereo pilot and RDS should remain
|
||||
|
||||
### audio_preamp
|
||||
|
||||
Pre-amplification of the audio, before any filters, set to 1 by default, set to 0 to mute audio
|
||||
|
||||
### deviation
|
||||
|
||||
Set the deviation, you can use this to easily change to 50 KHz deviation if needed, by default 75 KHz, under the hood it just sets the master volume to x/75000. Expects unit in Hz
|
||||
|
||||
### tilt
|
||||
|
||||
This is needed for most DACs, as they have output high pass filtering for DC, such filtering is not phase-linear, for example when DC is played, it will slowly go back to 0, such filtering is bad for square waves and some bass, use calibration 2 to test for tilt, you can use a oscilloscope with a receiver or a RF spectrometer as well as a SDR, if in tilt, you should see a perfect square wave, a signal abruptly jumping between 1 and -1 on a oscilloscope or a signal jumping between -75 and 75 khz on a RF spectrum, for the setting itself this is a simple float with values between 0 (off) and 1
|
||||
|
||||
### bs412_max
|
||||
|
||||
This is usually not needed to set, but it sets the max gain for the BS412 compressor, so if it is the default 1, the BS412 compressor will never make the signal louder than it is on the input
|
||||
|
||||
### agc_target
|
||||
|
||||
Target of the AGC, usually not needed to set, defaults to 0.625 (higher is louder)
|
||||
|
||||
### agc_attack
|
||||
|
||||
How fast will the AGC react to the signal going over the target, unit in seconds
|
||||
|
||||
### agc_release
|
||||
|
||||
How fast will the AGC react to the signal going lesser than the target, in seconds
|
||||
|
||||
### agc_min
|
||||
|
||||
Default is 0.1, this is usually not needed, for what it does, see bs412_max, but instead of louder quieter, and not bs412 but agc
|
||||
|
||||
### agc_max
|
||||
|
||||
See agc_min, but its louder not quieter, and the default is 1.5
|
||||
|
||||
### bs412_attack
|
||||
|
||||
See agc_attack, but BS412, not AGC
|
||||
|
||||
### bs412_release
|
||||
|
||||
See bs412_attack, but its release instead
|
||||
|
||||
## advanced
|
||||
|
||||
### lpf_order
|
||||
|
||||
Sets the quality of the LPF, unless running on a weak system, this does not need change from the default 15 (lower is less cpu usage)
|
||||
|
||||
### preemp_unity
|
||||
|
||||
Sets the unity gain for preemphasis, if you don't know what that means you shouldn't touch this, but it defaults to 15 khz, unit in hz
|
||||
|
||||
### sample_rate
|
||||
|
||||
Default 192 khz, does not need change under most systems, and unit is in hz
|
||||
|
||||
### lpf_cutoff
|
||||
|
||||
lpf cutoff, some run this at 15, because Big FM™ tells them to, but running this higher has no costs (unless you're running it above 18.5 khz), but no gains either, unit in hz
|
||||
|
||||
50
src/fm95.c
50
src/fm95.c
@@ -315,26 +315,36 @@ static int config_handler(void* user, const char* section, const char* name, con
|
||||
pconfig->audio_preamp = strtof(value, NULL);
|
||||
} else if (MATCH("fm95", "deviation")) {
|
||||
pconfig->audio_deviation = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "tilt")) {
|
||||
pconfig->tilt = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "bs412_max")) {
|
||||
pconfig->bs412_max = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "agc_target")) {
|
||||
pconfig->agc_target = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "agc_attack")) {
|
||||
pconfig->agc_attack = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "agc_release")) {
|
||||
pconfig->agc_release = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "agc_min")) {
|
||||
pconfig->agc_min = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "agc_max")) {
|
||||
pconfig->agc_max = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "bs412_attack")) {
|
||||
pconfig->bs412_attack = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "bs412_release")) {
|
||||
pconfig->bs412_release = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "lpf_order")) {
|
||||
pconfig->lpf_order = atoi(value);
|
||||
} else if(MATCH("advanced", "preemp_unity")) {
|
||||
pconfig->preemp_unity_freq = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "sample_rate")) {
|
||||
pconfig->sample_rate = atoi(value);
|
||||
} else if(MATCH("advanced", "agc_target")) {
|
||||
pconfig->agc_target = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "agc_attack")) {
|
||||
pconfig->agc_attack = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "agc_release")) {
|
||||
pconfig->agc_release = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "agc_min")) {
|
||||
pconfig->agc_min = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "agc_max")) {
|
||||
pconfig->agc_max = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "bs412_attack")) {
|
||||
pconfig->bs412_attack = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "bs412_release")) {
|
||||
pconfig->bs412_release = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "lpf_cutoff")) {
|
||||
pconfig->lpf_cutoff = strtof(value, NULL);
|
||||
if(pconfig->lpf_cutoff > (pconfig->sample_rate * 0.5)) {
|
||||
pconfig->lpf_cutoff = (pconfig->sample_rate * 0.5);
|
||||
fprintf(stderr, "LPF cutoff over niquist, limiting.\n");
|
||||
}
|
||||
} else if(MATCH("volumes", "mono")) {
|
||||
pconfig->volumes.mono = strtof(value, NULL);
|
||||
} else if(MATCH("volumes", "pilot")) {
|
||||
@@ -345,16 +355,6 @@ static int config_handler(void* user, const char* section, const char* name, con
|
||||
pconfig->volumes.rds = strtof(value, NULL);
|
||||
} else if(MATCH("volumes", "rds_step")) {
|
||||
pconfig->volumes.rds_step = strtof(value, NULL);
|
||||
} else if(MATCH("fm95", "tilt")) {
|
||||
pconfig->tilt = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "bs412_max")) {
|
||||
pconfig->bs412_max = strtof(value, NULL);
|
||||
} else if(MATCH("advanced", "lpf_cutoff")) {
|
||||
pconfig->lpf_cutoff = strtof(value, NULL);
|
||||
if(pconfig->lpf_cutoff > (pconfig->sample_rate * 0.5)) {
|
||||
pconfig->lpf_cutoff = (pconfig->sample_rate * 0.5);
|
||||
fprintf(stderr, "LPF cutoff over niquist, limiting.\n");
|
||||
}
|
||||
} else {
|
||||
return 0; // Unknown section/name
|
||||
}
|
||||
@@ -502,7 +502,7 @@ int main(int argc, char **argv) {
|
||||
.bs412_attack = 0.05f,
|
||||
.bs412_release = 0.025,
|
||||
.bs412_max = 1.0f,
|
||||
.lpf_cutoff = 15000, // lpf cutoff, some run this at 15, because Big FM™ tells them to, but running this higher has no costs (unless you're running it above 18.5 khz), but no gains either
|
||||
.lpf_cutoff = 15000,
|
||||
};
|
||||
|
||||
FM95_DeviceNames dv_names = {
|
||||
|
||||
Reference in New Issue
Block a user