/* Spectroscopic Toolkit version 1.96, november 8, 2011. Copyright (c) 2000-2011 - Pieter Suurmond Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ST translates spectroscopic (i.e. quantumphysical) data to AIFF-file. Uses the binary database-file gfall.pbin, produced by the pconv-program that reads Robert Kurucz's latest data file (see subdirectory pconv). Play all frequencies of one element together, almost. Atomic.num: Suggested strength: Au = 7900, 0.92 Ag = 4700, 1.50 Fe = 2600, 0.18 Hg = 8000, 1.20 Sn = 5000, 1.12 Cu = 2900, 0.88 Pb = 8200, 1.40 Au+ = 7901, missing Ag+ = 4701, 1.20 Fe+ = 2601, 0.12 Hg+ = 8001, 1.10 Sn+ = 5001, 1.15 Cu+ = 2901, 0.20 Pb+ = 8201, 1.20 */ #include /* Standard headers. */ #include #include #include "ST_wavelets.h" /* Prototype addWAVELET(). */ #include "ST_pconv.h" #include "c00.h" /* To check prototypes. */ /*------------------------------------------------------------------------------------------------*/ short c01_massiveCloud(unsigned short selected, /* 100 * Atomic number + ionisation level. */ double strength, /* Linear overall amplitude (0.18=OK for Fe). */ short phase, /* -1=oscill.sync; 0=sin at top; 1=cos at top. */ long double starttime, /* Starttime in seconds. */ long double duration, /* 'effective duration' in seconds. */ ENGINEp E, FILE* msg) { FILE *pbinDatabaseFP; pieterPacked pbinBuff; derivedData more; /* See ST.gfall.pbin.c. */ unsigned long linesRead = 0, linesUsed = 0, linesSkipped = 0; short e = 0; double a, p, d; long double dur, audioHertz; double loFreq = 9.99E99, /* AUDIO-freq. */ hiFreq = -9.99E99, loAmp = 9.99E99, /* Hi-Hertz(!), not audio-amplitude yet. */ hiAmp = -9.99E99; double durA, durB; /* Slope & offset. Lowest freq->1; highest freq->0.5. */ /*------------------------------------------------------------ Frequency transposition: */ long double transpositionRatio = pow(2.0, -40.0); /* 40 octaves down. */ /*------------------------------------------------------------ Smoother frequency windowing: */ double lowestFreq = 20.0; /* (trapeziod instead of brickwall) */ double aboveLowestFreq = 1.25 * lowestFreq; /* Rise to 1 within 1 major third. */ double aboveHertz = aboveLowestFreq - lowestFreq; double nyquist = 0.5 * (double)getSamplerateENGINE(E); double belowNyquist = nyquist / 1.2; /* Fall to 0 within 1 minor third. */ double belowHertz = nyquist - belowNyquist; /*------------------------------------------------------- Open binary version of Kurucz's file. */ pbinDatabaseFP = fopen(kST_bin_base, "rb"); if (pbinDatabaseFP) { /*------------------------------ CYCLE #1 (analysis) ------------------*/ while (fread(&pbinBuff, sizeof(pbinBuff), 1, pbinDatabaseFP)) { if (selected == pbinBuff.ELEM) { moreLineData(&pbinBuff, &more); /* Calc some more data. */ audioHertz = more.frequency * transpositionRatio; /* Exclude out-of-range-freqs from analysis. */ /* There may slip through some freqs that will be too weak in the second step! */ if ((audioHertz > lowestFreq) && (audioHertz < nyquist)) { if (audioHertz < loFreq) loFreq = audioHertz; if (audioHertz > hiFreq) hiFreq = audioHertz; if (more.Avalue < loAmp) loAmp = more.Avalue; if (more.Avalue > hiAmp) hiAmp = more.Avalue; } } } /*--------------------- Print statistics for the selected metals: ------------*/ if (msg) fprintf(msg, "-------- c01_massiveCloud() element %d: --------\n\ loAmp = %.8f; hiAmp = %.8f; RATIO=%.2f.\nloFreq = %.6f; hiFreq = %.6f; RATIO=%.2f.\n", selected, loAmp, hiAmp, hiAmp / loAmp, loFreq, hiFreq, hiFreq / loFreq); /*---------------- Linear duration compensation function: ------------------------------*/ /* d(loF) = 1 1 = a loF + b a = 0.5 / (loF - hiF) */ /* d(hiF) = 0.5 0.5 = a hiF + b - 0.5 = (0.5 / (loF - hiF)) hiF + b */ /* d(F) = a F + b ------------------- b = 0.5 - (0.5 hiF / (loF - hiF)) */ /* 0.5 = a (loF - hiF) */ d = loFreq - hiFreq; durA = 0.5 / d; /* A=slope and B=offset. */ durB = 0.5 - (0.5 * hiFreq / d); /*---------------- Linear bass-boost-filter-function (per element): --------------------*/ /* SAME "d" as with duration may be used: highest freq (per element) gets -6.021 dB. */ /*---------------------------- CYCLE #2: Post (audio-)wavelets into linked list. -------*/ rewind(pbinDatabaseFP); if (msg) { fprintf(msg, "1/transpositionRatio = %.1Lf.\n", 1.0 / transpositionRatio); fprintf(msg, "'effective duration' = %.6Lf s.\n", duration); fprintf(msg, "Using phase = %d.\n", (int)phase); } while (fread(&pbinBuff, sizeof(pbinBuff), 1, pbinDatabaseFP)) { /*----------------------------------------------- ELEMENT / ION - selector: */ if (selected == pbinBuff.ELEM) { moreLineData(&pbinBuff, &more); /* Calc some more data. */ /*----------------------------------------------------------------------*/ audioHertz = more.frequency * transpositionRatio; if ((audioHertz > lowestFreq) && (audioHertz < nyquist)) { /*------------------ Less brickwall-shaped filtering: --------------*/ if (audioHertz < aboveLowestFreq) a = (audioHertz - lowestFreq) / aboveHertz; /* Rise to 1 within 1 minor third. */ else if (audioHertz > belowNyquist) a = (nyquist - audioHertz) / belowHertz; /* Fall to 0 within 1 major third. */ else a = 1.0; /*---------------- Frequency-dependant Compensation per element: ---------------*/ /* Only lowest freq of selected element gets unit-duration and unit-amplit., */ /* all higher frequencies sound shorter. loFreq -> 1, hiFreq -> 0.5. */ d = (durA * audioHertz) + durB; /*------------------ Bass boost-filter (per element): --------------*/ a *= d; /* Highest frequency per element -6.021 dB. */ /* ----------------- Amplitude: ------------------------------------*/ /* Compress amplitude-range by approx 4th-power-root. */ a *= strength * pow(1.90e-13 * more.Avalue, 0.26); /*-------------------- Amplitude treshold (23 bit) -----------------*/ if (a >= 1.192093E-7) { /*------------------------ Panning: ---------------------------------------*/ if (pbinBuff.LOW.J == pbinBuff.UPP.J) p = 0.0; else if (pbinBuff.LOW.J > pbinBuff.UPP.J) /* Depend upon quantum-states. */ p = +0.5; else p = -0.5; if (linesUsed & 1L) /* Alternate between left and right channel. */ p += 0.118; else p -= 0.118; /*---------------- Duration & starttime: ---------------------------*/ dur = duration * d; /* Only lowest freq gets unit-duration. */ if (addWAVELET(E, msg, 0, /* Hz */ audioHertz, /* amp */ a, /* pan */ p, /* top */ starttime + (0.5 * dur), /* All start-inflections together. */ /* dur */ dur, /* Top at starttime + DUR/2. */ /* env */ kENV_Gaussian, /* pha */ phase)) /* -1 = sync with other oscillators. */ { if (msg) fprintf(msg, "Illegal wavelet!\n"); e = 3; goto clFile; } linesUsed++; } else { linesSkipped++; if (msg) fprintf(msg, "SKIPPED-AMP %d: Hz=%12.6Lf lggf=%5.2f.\n", pbinBuff.ELEM, audioHertz, pbinBuff.LOGGF); } } else { linesSkipped++; if (msg) fprintf(msg, "SKIPPED-FRQ %d: Hz=%12.6Lf lggf=%5.2f.\n", pbinBuff.ELEM, audioHertz, pbinBuff.LOGGF); } printLineEssential(&pbinBuff, msg); /* NULL, stdout or some FILE*. */ printLineDerived(&more, msg); } linesRead++; } if (msg) fprintf(msg, " linesUsed = %ld.\nlinesSkipped = %ld.\n", linesUsed, linesSkipped); if (linesRead != kKuruczLinesTotal) { if (msg) fprintf(msg, "Error reading binary database lines!\n"); e = 2; } clFile: fclose(pbinDatabaseFP); } else { if (msg) fprintf(msg, "Could not open binary database file '%s'!\n", kST_bin_base); e = 1; } return(e); } /*----------------------------------------------------------------------------*/ /* Several functions which are accessable from the user interface: separate clouds for Paul Glazier (for Ruhrlandmuseum in Essen), october 2004. We try to maximise output amplitudes here (16 bit). Duration twice as long (42.1875 s) seems too long, especially for gold. */ /* Effective duration in seconds. */ #define kSEPARATE_CLOUD_DURATION (21.09375) /* 24.0 * 60.0 * 60.0 / 4096.0. */ #define kSEPARATE_CLOUD_STARTTIME ((kSEPARATE_CLOUD_DURATION * 2.0) + 0.001) /* We need 1 ms margin, due to ROUNDING EFFECTS! in starttime calculations! */ short c01_os_cloud_H(ENGINEp E, FILE* msg) /* Hydrogen (too dissonant). */ { return c01_massiveCloud(100, /* 100 * atomic number + ionisation level. */ 1.00, /* 1.00=ok Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_He(ENGINEp E, FILE* msg) /* Helium. */ { return c01_massiveCloud(200, /* 100 * atomic number + ionisation level. */ 0.70, /* 0.70=ok Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_HeP(ENGINEp E, FILE* msg) /* Helium+ ion. */ { return c01_massiveCloud(201, /* 100 * atomic number + ionisation level. */ 0.50, /* 0.50=ok Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Li(ENGINEp E, FILE* msg) /* Lithium. */ { return c01_massiveCloud(300, /* 100 * atomic number + ionisation level. */ 1.00, /* 1.00=ok Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Be(ENGINEp E, FILE* msg) /* Beryllium. */ { return c01_massiveCloud(400, /* 100 * atomic number + ionisation level. */ 1.92, /* 1.92=ok 99.54% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_B(ENGINEp E, FILE* msg) /* Boron. */ { return c01_massiveCloud(500, /* 100 * atomic number + ionisation level. */ 1.83, /* 1.83=ok 99.68% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_C(ENGINEp E, FILE* msg) /* Carbon. */ { return c01_massiveCloud(600, /* 100 * atomic number + ionisation level. */ 0.40, /* 0.40=ok-->peak=85.31% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_N(ENGINEp E, FILE* msg) /* Nitrogen. */ { return c01_massiveCloud(700, /* 100 * atomic number + ionisation level. */ 0.43, /* 0.43-->peak=99.51%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_O(ENGINEp E, FILE* msg) /* Oxygen. */ { return c01_massiveCloud(800, /* 100 * atomic number + ionisation level. */ 0.40, /* 0.40-->98.73% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_F(ENGINEp E, FILE* msg) /* Fluorine. */ { return c01_massiveCloud(900, /* 100 * atomic number + ionisation level. */ 0.60, /* 0.60-->98.97% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Ne(ENGINEp E, FILE* msg) /* Neon. */ { return c01_massiveCloud(1000, /* 100 * atomic number + ionisation level. */ 0.60, /* 0.60-->98.28% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Na(ENGINEp E, FILE* msg) /* Sodium. */ { return c01_massiveCloud(1100, /* 100 * atomic number + ionisation level. */ 1.30, /* 1.30-->99.81% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Mg(ENGINEp E, FILE* msg) /* Magnesium. */ { return c01_massiveCloud(1200, /* 100 * atomic number + ionisation level. */ 0.50, /* 0.50-->98.31% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Al(ENGINEp E, FILE* msg) /* Aluminium. */ { return c01_massiveCloud(1300, /* 100 * atomic number + ionisation level. */ 1.09, /* 1.09-->99.10% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Si(ENGINEp E, FILE* msg) /* Silicon. */ { return c01_massiveCloud(1400, /* 100 * atomic number + ionisation level. */ 0.37, /* 0.37-->98.42% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_P(ENGINEp E, FILE* msg) /* Phosphorus. */ { return c01_massiveCloud(1500, /* 100 * atomic number + ionisation level. */ 0.66, /* 0.66-->98.59% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_S(ENGINEp E, FILE* msg) /* Sulfer. */ { return c01_massiveCloud(1600, /* 100 * atomic number + ionisation level. */ 0.74, /* 0.74-->99.42% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Cl(ENGINEp E, FILE* msg) /* Chlorine. */ { return c01_massiveCloud(1700, /* 100 * atomic number + ionisation level. */ 0.39, /* 0.39-->98.00% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Ar(ENGINEp E, FILE* msg) /* Argon. */ { return c01_massiveCloud(1800, /* 100 * atomic number + ionisation level. */ 0.63, /* 0.63-->99.76% Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Fe(ENGINEp E, FILE* msg) /* Iron. */ { return c01_massiveCloud(2600, /* 100 * atomic number + ionisation level. */ 0.20, /* 0.20-->96.11%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Co(ENGINEp E, FILE* msg) /* Cobalt. */ { return c01_massiveCloud(2700, /* 100 * atomic number + ionisation level. */ 0.30, /* 0.30-->93.09%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Ni(ENGINEp E, FILE* msg) /* Nickel. */ { return c01_massiveCloud(2800, /* 100 * atomic number + ionisation level. */ 0.39, /* 0.39-->99.33%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Cu(ENGINEp E, FILE* msg) /* Copper. */ { return c01_massiveCloud(2900, /* 100 * atomic number + ionisation level. */ 1.03, /* 1.03-->99.52%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Zn(ENGINEp E, FILE* msg) /* Zinc. */ { return c01_massiveCloud(3000, /* 100 * atomic number + ionisation level. */ 1.88, /* 1.88-->99.61%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Ag(ENGINEp E, FILE* msg) /* Silver. */ { return c01_massiveCloud(4700, /* 100 * atomic number + ionisation level. */ 3.13, /* 3.13-->99.77%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Sn(ENGINEp E, FILE* msg) /* Tin. */ { return c01_massiveCloud(5000, /* 100 * atomic number + ionisation level. */ 1.71, /* 1.71-->99.99%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } /* 5300, Iodine is missing in the database! */ /* 5400, Xenon is missing in the database! */ short c01_os_cloud_Cs(ENGINEp E, FILE* msg) /* Cesium */ { return c01_massiveCloud(5500, /* 100 * atomic number + ionisation level. */ 2.34, /* 2.34-->99.95%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Au(ENGINEp E, FILE* msg) /* Gold */ { return c01_massiveCloud(7900, /* 100 * atomic number + ionisation level. */ 1.78, /* 1.78-->peak=99.88%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Hg(ENGINEp E, FILE* msg) /* Mercury. */ { return c01_massiveCloud(8000, /* 100 * atomic number + ionisation level. */ 1.84, /* 1.84-->99.59%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_Pb(ENGINEp E, FILE* msg) /* Lead. */ { return c01_massiveCloud(8200, /* 100 * atomic number + ionisation level. */ 1.88, /* 1.88-->99.94%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } /* 8800, Radium is missing in the database! */ short c01_os_cloud_Th(ENGINEp E, FILE* msg) /* Thorium. */ { return c01_massiveCloud(9000, /* 100 * atomic number + ionisation level. */ 0.77, /* 0.77->98.92%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_os_cloud_U(ENGINEp E, FILE* msg) /* Uranium. */ { return c01_massiveCloud(9200, /* 100 * atomic number + ionisation level. */ 0.80, /* 0.80->91.99%. Linear overall amplitude. */ -1, /* -1 = oscillator sync. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } /* 9400, Plutonium is missing in the database! */ /* NIEUW 2011 --------------------------------------------------------------------------- 36 krypton (85) 38 strontium (90) ---------------------------------------------------------------------------*/ /*======================== And the same, but now with envelope-aligned phases: ============*/ short c01_cloud_H(ENGINEp E, FILE* msg) /* Hydrogen. */ { return c01_massiveCloud(100, /* 100 * atomic number + ionisation level. */ 0.80, /* 0.80=ok-->peak=90.31%. Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_cloud_He(ENGINEp E, FILE* msg) /* Helium. */ { return c01_massiveCloud(200, /* 100 * atomic number + ionisation level. */ 0.35, /* 0.35=ok (-32042 (97.78%)) Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_cloud_HeP(ENGINEp E, FILE* msg) /* Helium+ ion. */ { return c01_massiveCloud(201, /* 100 * atomic number + ionisation level. */ 0.60, /* 0.60=ok (-32331 (98.67%)) Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_cloud_Li(ENGINEp E, FILE* msg) /* Lithium. */ { return c01_massiveCloud(300, /* 100 * atomic number + ionisation level. */ 0.72, /* 0.72=ok: 93.72% Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_cloud_C(ENGINEp E, FILE* msg) /* Carbon. */ { return c01_massiveCloud(600, /* 100 * atomic number + ionisation level. */ 0.25, /* 0.25=ok-->peak=-30567 == 93.28% Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_cloud_N(ENGINEp E, FILE* msg) /* Nitrogen. */ { return c01_massiveCloud(700, /* 100 * atomic number + ionisation level. */ 0.30, /* 0.30=ok (-32321 (98.64%)) Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_cloud_O(ENGINEp E, FILE* msg) /* Oxygen. */ { return c01_massiveCloud(800, /* 100 * atomic number + ionisation level. */ 0.39, /* 0.39=ok (-32037 (97.77%)) Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_cloud_F(ENGINEp E, FILE* msg) /* Fluorine. */ { return c01_massiveCloud(900, /* 100 * atomic number + ionisation level. */ 0.54, /* 0.54=ok () Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_cloud_Si(ENGINEp E, FILE* msg) /* Silicon. */ { return c01_massiveCloud(1400, /* 100 * atomic number + ionisation level. */ 0.26, /* 0.26=ok (-32026 (97.74%)) Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } short c01_cloud_S(ENGINEp E, FILE* msg) /* Sulfer. */ { return c01_massiveCloud(1600, /* 100 * atomic number + ionisation level. */ 0.50, /* 0.50=ok (-32533 (99.28%)) Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } /* 7 alchemistic metals: */ short c01_cloud_Au(ENGINEp E, FILE* msg) /* Gold. */ { return c01_massiveCloud(7900, /* 100 * atomic number + ionisation level. */ 1.78, /* 1.78=ok-->peak=98.28%. Linear overall amplitude. */ 1, /* +1 = zero-phase cosines aligned at TOP. */ (kSEPARATE_CLOUD_STARTTIME), (kSEPARATE_CLOUD_DURATION), E, msg); } /*------------------------------------------------------------------------------------------------*/ short c01_shapedCloud(unsigned short selected, /* 100 * Atomic number + ionisation level. */ double strength, /* Linear overall amplitude (0.18=OK for Fe). */ long double starttime, /* Starttime in seconds. */ long double duration, /* 'effective duration' in seconds. */ const double* shapeFreqs, /* Array with frequencies (- earlier, + later) */ ENGINEp E, FILE* msg) { FILE *pbinDatabaseFP; pieterPacked pbinBuff; derivedData more; /* See ST.gfall.pbin.c. */ unsigned long linesRead = 0, linesUsed = 0, linesSkipped = 0; short e = 0; double a, p, inflectStart, d; long double audioHertz, dur; double loFreq = 9.99E99, /* AUDIO-freq. */ hiFreq = -9.99E99, loAmp = 9.99E99, /* Hi-Hertz(!), not audio-amplitude yet. */ hiAmp = -9.99E99; double durA, durB; /* Slope & offset. Lowest freq->1; highest freq->0.5. */ double shF, shD, corr, shCorr; const double *shapeF, shapeRatio = 1.12; /* About a whole tone around center-frequencies. */ /*------------------------------------------------------------ Frequency transposition: */ long double transpositionRatio = pow(2.0, -40.0); /* 40 octaves down. */ /*------------------------------------------------------------ Smoother frequency windowing: */ double lowestFreq = 20.0; /* (trapeziod instead of brickwall) */ double aboveLowestFreq = 1.25 * lowestFreq; /* Rise to 1 within 1 major third. */ double aboveHertz = aboveLowestFreq - lowestFreq; double nyquist = 0.5 * (double)getSamplerateENGINE(E); double belowNyquist = nyquist / 1.2; /* Fall to 0 within 1 minor third. */ double belowHertz = nyquist - belowNyquist; /*------------------------------------------------------- Open binary version of Kurucz's file. */ pbinDatabaseFP = fopen(kST_bin_base, "rb"); if (pbinDatabaseFP) { /*------------------------------ CYCLE #1 (analysis) ------------------*/ while (fread(&pbinBuff, sizeof(pbinBuff), 1, pbinDatabaseFP)) { if (selected == pbinBuff.ELEM) { moreLineData(&pbinBuff, &more); /* Calc some more data. */ audioHertz = more.frequency * transpositionRatio; /* Exclude out-of-range-freqs from analysis. */ /* There may slip through some freqs that will be too weak in the second step! */ if ((audioHertz > lowestFreq) && (audioHertz < nyquist)) { if (audioHertz < loFreq) loFreq = audioHertz; if (audioHertz > hiFreq) hiFreq = audioHertz; if (more.Avalue < loAmp) loAmp = more.Avalue; if (more.Avalue > hiAmp) hiAmp = more.Avalue; } } } /*--------------------- Print statistics for the selected metals: ------------*/ if (msg) fprintf(msg, "-------- c01_massiveCloud() element %d: --------\n\ loAmp = %.8f; hiAmp = %.8f; RATIO=%.2f.\nloFreq = %.6f; hiFreq = %.6f; RATIO=%.2f.\n", selected, loAmp, hiAmp, hiAmp / loAmp, loFreq, hiFreq, hiFreq / loFreq); /*---------------- Linear duration compensation function: ------------------------------*/ /* d(loF) = 1 1 = a loF + b a = 0.5 / (loF - hiF) */ /* d(hiF) = 0.5 0.5 = a hiF + b - 0.5 = (0.5 / (loF - hiF)) hiF + b */ /* d(F) = a F + b ------------------- b = 0.5 - (0.5 hiF / (loF - hiF)) */ /* 0.5 = a (loF - hiF) */ d = loFreq - hiFreq; durA = 0.5 / d; /* A=slope and B=offset. */ durB = 0.5 - (0.5 * hiFreq / d); /*---------------- Linear bass-boost-filter-function (per element): --------------------*/ /* SAME "d" as with duration may be used: highest freq (per element) gets -6.021 dB. */ /*---------------------------- CYCLE #2: Post (audio-)wavelets into linked list. -------*/ rewind(pbinDatabaseFP); if (msg) { fprintf(msg, "1/transpositionRatio = %.1Lf.\n", 1.0 / transpositionRatio); fprintf(msg, "'effective duration' = %.6Lf s.\n", duration); fprintf(msg, "Using oscillator-sync. (phase = -1).\n"); } while (fread(&pbinBuff, sizeof(pbinBuff), 1, pbinDatabaseFP)) { /*----------------------------------------------- ELEMENT / ION - selector: */ if (selected == pbinBuff.ELEM) { moreLineData(&pbinBuff, &more); /* Calc some more data. */ /*----------------------------------------------------------------------*/ audioHertz = more.frequency * transpositionRatio; if ((audioHertz > lowestFreq) && (audioHertz < nyquist)) { /*------------------ Less brickwall-shaped filtering: --------------*/ if (audioHertz < aboveLowestFreq) a = (audioHertz - lowestFreq) / aboveHertz; /* Rise to 1 within 1 minor third. */ else if (audioHertz > belowNyquist) a = (nyquist - audioHertz) / belowHertz; /* Fall to 0 within 1 major third. */ else a = 1.0; /*---------------- Frequency-dependant Compensation per element: ---------------*/ /* Only lowest freq of selected element gets unit-duration and unit-amplit., */ /* all higher frequencies sound shorter. loFreq -> 1, hiFreq -> 0.5. */ d = (durA * audioHertz) + durB; /*------------------ Bass boost-filter (per element): --------------*/ a *= d; /* Highest frequency per element -6.021 dB. */ /* ----------------- Amplitude: ------------------------------------*/ /* Compress amplitude-range by approx 4th-power-root. */ a *= strength * pow(1.90e-13 * more.Avalue, 0.26); /*-------------------- Amplitude treshold (23 bit) -----------------*/ if (a >= 1.192093E-7) { /*------------------------ Panning: ---------------------------------------*/ if (pbinBuff.LOW.J == pbinBuff.UPP.J) p = 0.0; else if (pbinBuff.LOW.J > pbinBuff.UPP.J) /* Depend upon quantum-states. */ p = +0.5; else p = -0.5; if (linesUsed & 1L) /* Alternate between left and right channel. */ p += 0.118; else p -= 0.118; /*---------------- Shaping: -------------------------------------*/ shCorr = 0.0; /* Regions may overlap. */ shapeF = shapeFreqs; while ((shF = fabs(*shapeF)) > 1.0) /* <= 1 terminates array. */ { shD = audioHertz / shF; if (shD < 1.0) shD = 1.0 / shD; if (shD < shapeRatio) /* Within a semitone. */ { /* shD: 1.0 ... 1.059. */ /* corr = 1.0 - (log(shD) / log(shapeRatio)); 1.0 ... 0.000. */ corr = 1.0 - ((shD - 1.0) / (shapeRatio - 1.0)); corr *= corr; /* 4th power makes better shape. */ corr *= corr; if (*shapeF < 0.0) shCorr -= corr; /* Total correction may exceed 1.0 ! */ else shCorr += corr; } shapeF++; } if (msg && (shCorr != 0.0)) fprintf(msg, "shCorr = %.4f\n", shCorr); /*---------------- Duration & starttime: ---------------------------*/ dur = duration * d; /* Only lowest freq gets unit-duration. */ inflectStart = starttime + (shCorr * dur * 0.36); /* 0.60 is a bit too much. */ if (addWAVELET(E, msg, 0, /* Hz */ audioHertz, /* amp */ a, /* pan */ p, /* top */ inflectStart + (0.5 * dur), /* All start-inflections together. */ /* dur */ dur, /* Top at inflectstart + DUR/2. */ /* env */ kENV_Gaussian, /* pha */ -1)) /* -1 = sync with other oscillators. */ { if (msg) fprintf(msg, "Illegal wavelet!\n"); e = 3; goto clFile; } linesUsed++; } else { linesSkipped++; if (msg) fprintf(msg, "SKIPPED-AMP %d: Hz=%12.6Lf lggf=%5.2f.\n", pbinBuff.ELEM, audioHertz, pbinBuff.LOGGF); } } else { linesSkipped++; if (msg) fprintf(msg, "SKIPPED-FRQ %d: Hz=%12.6Lf lggf=%5.2f.\n", pbinBuff.ELEM, audioHertz, pbinBuff.LOGGF); } printLineEssential(&pbinBuff, msg); /* NULL, stdout or some FILE*. */ printLineDerived(&more, msg); } linesRead++; } if (msg) fprintf(msg, " linesUsed = %ld.\nlinesSkipped = %ld.\n", linesUsed, linesSkipped); if (linesRead != kKuruczLinesTotal) { if (msg) fprintf(msg, "Error reading binary database lines!\n"); e = 2; } clFile: fclose(pbinDatabaseFP); } else { if (msg) fprintf(msg, "Could not open binary database-file '%s'!\n", kST_bin_base); e = 1; } return e; }